简体   繁体   English

如何编写使用括号而不是方括号来编辑数组/哈希的方法?

[英]How do I write a method to edit an array/hash using parentheses instead of square brackets?

I'm trying to write an internal DSL in Ruby and am running into trouble with implementing a particular syntax. 我试图用Ruby编写内部DSL,并且在实现特定语法时遇到麻烦。 Specifically, if I have an array (or hash) in a class, I'd like to access and edit it with parentheses. 具体来说,如果我在一个类中有一个数组(或哈希),我想用括号来访问和编辑它。 For example: 例如:

class MyData
  attr_accessor :things
  def initialize
    @things = ['right', 'right', 'wrong']
  end
end

test = MyData.new

# This obviously won't work, but it's the syntax that I want.
test.things(2) = 'right'

I know I can read an element with this syntax by doing: 我知道我可以通过以下方式读取具有此语法的元素:

class MyData
  def things(index)
    @things[index]
  end
end

test = MyData.new
test.things(2) # => 'wrong' 

but actually changing the element is another thing entirely because Ruby just doesn't know what to do with that assignment operator. 但是实际上更改元素完全是另一回事,因为Ruby只是不知道如何处理该赋值运算符。

The reason I want this strange syntax is because I hope I can use this language to easily convert some Fortran namelist files into a friendly Ruby environment, and Fortran unfortunately indexes arrays with parentheses. 我想要这种奇怪的语法的原因是因为我希望我可以使用这种语言轻松地将某些Fortran名称列表文件转换为友好的Ruby环境,并且Fortran不幸地使用括号对数组进行了索引。

My fear is that this is just one of those situations where I'm trying too hard to make Ruby go against its core syntax and I'll need to actually write a parser. 我担心这只是我为使Ruby违背其核心语法而付出的最大努力之一,而我实际上需要编写一个解析器。 Any thoughts? 有什么想法吗?

The syntax isn't valid Ruby, ergo you cannot do that in Ruby. 该语法在Ruby中无效,因此您不能在Ruby中执行该操作。 Period. 期。

You have several options: 您有几种选择:

  1. Change your syntax to something that is valid Ruby: 将语法更改有效的Ruby:

     class MyData attr_reader :things private attr_writer :things def initialize self.things = %w[right right wrong] end end test = MyData.new test.things[2] = 'right' test.things # => ['right', 'right', 'right'] 
  2. Use a language that supports that syntax, like Scala: 使用支持该语法的语言,例如Scala:

     class MyData { var things = scala.collection.mutable.Seq("right", "right", "wrong") } val test = new MyData test.things(2) = "right" test.things // => scala.collection.mutable.Seq[String] = ArrayBuffer(right, right, right) 
  3. Create an external DSL, ie one that isn't valid Ruby. 创建一个外部DSL,即无效的Ruby。

    In fact, it looks like what you have already is a well-defined external DSL, specifically a subset of Fortran. 实际上,看起来您已经拥有的定义良好的外部DSL,尤其是Fortran的子集。 Depending on whether or not you have control over those namelist files, you may even be able to restrict the syntax further to something that is quite trivially parseable with some Regexp s and a bit of text munging. 根据您是否可以控制这些名称列表文件,您甚至可以进一步限制语法,使其只能使用某些Regexp和一些文本修饰来轻松解析。

The call operator () cannot be overloaded so what you want to do technically cannot be done. 调用运算符()不能重载,因此从技术上讲您想做的事情无法完成。 An option would be to pre-process your DSL to replace parentheses with brackets before you hand it over to Ruby. 一种选择是在将DSL移交给Ruby之前对其进行预处理,以用括号替换括号。

Check out this other answer on operator overloading for more info. 查看有关操作符重载的其他答案 ,以获取更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM