加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

用ruby链接的方法

发布时间:2020-12-17 03:41:04 所属栏目:百科 来源:网络整理
导读:我想构建一个具有类似rails活动记录的接口的API客户端.我希望消费者能够链接方法,并且在最后一个方法被链接之后,客户端基于所调用的方法请求URL.所以它的方法是链接一些懒惰的评估.我查看了 Active Record,但这非常复杂(产卵过程等). 这是我正在谈论的那种事
我想构建一个具有类似rails活动记录的接口的API客户端.我希望消费者能够链接方法,并且在最后一个方法被链接之后,客户端基于所调用的方法请求URL.所以它的方法是链接一些懒惰的评估.我查看了 Active Record,但这非常复杂(产卵过程等).

这是我正在谈论的那种事情的玩具示例.你可以在调用’get’之前将任意数量的’bar’方法链接在一起,如下所示:

puts Foo.bar.bar.get # => 'bar,bar'
puts Foo.bar.bar.bar.get # => 'bar,bar,bar'

我已经成功实现了这个,但我宁愿不需要调用’get’方法.所以我想要的是:

puts Foo.bar.bar # => 'bar,bar'

但我目前的实现是这样做的:

puts Foo.bar.bar #=> [:bar,:bar]

我曾想过覆盖像each和to_s这样的数组方法,但我确信有更好的解决方案.

我如何链接方法并知道哪个是最后一个,所以我可以返回类似get方法中返回的字符串?

这是我目前的实施:

#!/usr/bin/env ruby

class Bar
  def get(args)
    # does a request to an API and returns things but this will do for now.
    args.join(',') 
  end
end

class Foo < Array
  def self.bar
    @q = new
    @q << :bar
    @q
  end

  def bar
    self << :bar
    self
  end

  def get
    Bar.new.get(self)
  end
end

另见:Ruby Challenge – Method chaining and Lazy Evaluation

解决方法

它与activerecord的工作原理是,该关系是数组的包装器,将任何未定义的方法委托给这个内部数组(称为目标).所以你需要的是从BasicObject而不是Object开始:

class Foo < BasicObject

那么你需要创建内部变量,你将委托所有方法:

def method_missing(*args,&block)
    reload! unless loaded?
    @target.send(*args,&block)
  end

  def reload!
    # your logic to populate target,e.g:
    @target = @counter
    @loaded = true
  end

  def loaded?
    !!@loaded
  end

要链接方法,您的方法需要返回类的新实例,例如:

def initialize(counter=0)
  @counter = counter
end

def bar
  _class.new(@counter + 1)
end

private

# BasicObject does not define class method. If you want to wrap your target 
# completely (like ActiveRecord does before rails 4),you want to delegate it 
# to @target as well. Still you need to access the instance class to create 
# new instances. That's the way (if there are any suggestion how to improve it,# please comment!)
def _class
  (class << self; self end).superclass
end

现在您可以检查它的实际效果:

p Foo.new.bar.bar.bar      #=> 3
(f = Foo.new) && nil       # '&& nil' added to prevent execution of inspect             
                           # object in the console,as it will force @target 
                           # to be loaded

f.loaded?                  #=> false
puts f                     #=> 0
f.loaded?                  #=> true

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读