标签: refinements

将ruby类转换为模块而不是使用细化的更好方法?

Module#refine method接受一个类和一个块并返回一个细化模块,所以我想我可以定义:

class Class
  def include_refined(klass)
    _refinement = Module.new do
      include refine(klass) {
        yield if block_given?
      }
    end
    self.send :include, _refinement
  end
end
Run Code Online (Sandbox Code Playgroud)

并且以下测试通过

class Base
  def foo
    "foo"
  end
end

class Receiver
  include_refined(Base) {
    def foo
      "refined " + super
    end
  }
end

describe Receiver do
  it { should respond_to(:foo) }
  its(:foo) { should eq("refined foo") }
end
Run Code Online (Sandbox Code Playgroud)

因此,使用细化,我可以将类转换为模块,动态改进其行为,并将其包含在其他类中.

  • 是否有一种更简单的方法可以将类转换为Ruby中的模块(比如ruby <2)?
  • rb_mod_refine的C实现中 我们看到了

    refinement = rb_module_new();
    RCLASS_SET_SUPER(refinement, klass);
    
    Run Code Online (Sandbox Code Playgroud)

    这只是将精炼的超类设置为klass复制模块中的类的实现吗?

  • 我知道多重继承是通过模块完成的,但是社区会怎么想Class#include_refined?从改进中提取这个方面是否合理?在本地"修补"而不是使用"使用"开关激活优化?

ruby ruby-2.0 refinements

25
推荐指数
1
解决办法
1625
查看次数

优化是否仅适用于实例方法?

我正在尝试理解Ruby的改进功能,我遇到了一个我不理解的场景.

以此示例代码为例:

class Traveller
  def what_are_you
    puts "I'm a Backpacker"
  end

  def self.preferred_accommodation
    puts "Hostels"
  end
end


module Refinements
  module Money
    def what_are_you
      puts "I'm a cashed-up hedonist!"
    end

    module ClassMethods
      def preferred_accommodation
        puts "Expensive Hotels"
      end
    end

    def self.included(base)
      base.extend ClassMethods
    end
  end

  refine Traveller do
    include Money
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,当我在REPL中执行此操作时:

Traveller.new.what_are_you         # => I'm a Backpacker
Traveller.preferred_accommodation  # => Hostels

using Refinements

Traveller.new.what_are_you         # => I'm a cashed-up hedonist!
Traveller.preferred_accommodation  # => Hostels (???)
Run Code Online (Sandbox Code Playgroud)

为什么#what_are_you精致,但.preferred_accommodation …

ruby refinements

13
推荐指数
2
解决办法
1491
查看次数

如何在Rails视图中使用Ruby优化?

我有一个使用Ruby 2.0的Rails 4项目.我已经定义了一些改进.把

<% using MyRefinements %>
Run Code Online (Sandbox Code Playgroud)

在视图文件的顶部导致错误"未定义的方法'使用'".

当我添加:

using MyRefinements
Run Code Online (Sandbox Code Playgroud)

在我的控制器的顶部(在类声明之上),我可以成功地使用控制器中的细化,但是如果我尝试在视图中使用它,我会收到"未定义的方法"错误.

谢谢!

ruby-2.0 ruby-on-rails-4 refinements

9
推荐指数
1
解决办法
545
查看次数

Ruby精炼细微之处

这里有关于ruby中当前优化实现的很好的文档:http: //ruby-doc.org//core-2.2.0/doc/syntax/refinements_rdoc.html,但是有一些奇怪的极端情况.

首先,include module正交using module(一个包括模块的实例方法,而另一个包括激活细化).但是有一个技巧包括一个改进模块本身,请参阅 更好的方法将ruby类转换为模块而不是使用细化?.

def to_module(klass)
  Module.new do
    #note that we return the refinement module itself here
    return refine(klass) {
      yield if block_given?
    }
  end
end

class Base
  def foo
    "foo"
  end
end
class Receiver
  include to_module(Base) {
    def foo
      "refined " + super
    end
  }
end
Receiver.new.foo #=> "refined foo"
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这个改进模块不能用using!

m=to_module(Base) {}
m.class #=> Module
using m    
#=>TypeError: wrong argument type Class (expected Module)
Run Code Online (Sandbox Code Playgroud)

因此,仅使用细化模块的封闭模块.其次我想使用上面的yi​​eld技巧来传递一个Proc来改进(即使它只接受一个块),而不是像在https://www.new-bamboo.co中 …

ruby refinements

7
推荐指数
1
解决办法
437
查看次数

Ruby精炼和钩子

我正在尝试使用ruby refinements来应用rails hooks.

我想避免猴子补丁.当猴子修补它会这样工作

ActiveRecord::Base.class_eval do
  after_find do 
     # do something with 
     my_method
  end

  def my_method
    # something useful
  end
end
Run Code Online (Sandbox Code Playgroud)

通过这样的方式,我已经能够拥有类方法:

module ActiveRecordRefinements
  refine ActiveRecord::Base.singleton_class do
    def my_method
     #something cool
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

但我无法逃脱.我尝试过使用self.used(klass)但似乎无法正确使用语法.

欢迎任何帮助.

谢谢.

ruby ruby-on-rails refinements

7
推荐指数
1
解决办法
160
查看次数

当我在IRB中使用精炼时,为什么我得到"main.using只允许在顶层使用"?

我试图在IRB中使用Refinement(v0.9.6,Ruby 2.3.0):

module Foo
  refine Object do
    def foo() "foo" end
  end
end

using Foo # => RuntimeError: main.using is permitted only at toplevel
Run Code Online (Sandbox Code Playgroud)

这基本上是文档中的确切设置(导致相同的错误).

什么地方出了错?我该如何解决?

ruby irb refinements

6
推荐指数
1
解决办法
832
查看次数

分层使用细化

精化是对v2.0的实验性补充,然后在v2.1中进行了修改并永久化.它提供了一种通过提供"在本地扩展类的方法"来避免"猴子修补"的方法.

我试图申请Refinements这个最近的问题,我将因此简化:

a = [[1, "a"],
     [2, "b"],
     [3, "c"],
     [4, "d"]]

b = [[1, "AA"],
     [2, "B"],
     [3, "C"],
     [5, "D"]]
Run Code Online (Sandbox Code Playgroud)

在位置的元素ia的元素相匹配的偏移ib,如果:

a[i].first == b[i].first
Run Code Online (Sandbox Code Playgroud)

a[i].last.downcase == b[i].last.downcase
Run Code Online (Sandbox Code Playgroud)

换句话说,字符串的匹配与大小写无关.

问题是确定a匹配相应元素的元素数量b.我们看到答案是两个,即抵消的元素12.

一种方法是使用Monkey-patch String#==:

class String
  alias :dbl_eql :==
  def ==(other)
    downcase.dbl_eql(other.downcase)
  end
end

a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
  #=> 2
Run Code Online (Sandbox Code Playgroud)

或者改为使用Refinements: …

ruby refinements

5
推荐指数
1
解决办法
124
查看次数

为什么to_proc不在Ruby优化中工作?

它似乎to_proc不适用于优化中定义的方法:

module ArrayExtensions
  refine Array do
    def sum
      reduce(0, :+)
    end
  end
end

using ArrayExtensions

puts [[1, 2, 3]].map { |array| array.sum } # => 6
puts [[1, 2, 3]].map(&:sum) # => array.rb:13:in `map': undefined method `sum' for [1, 2, 3]:Array (NoMethodError)
puts [1, 2, 3].method(:sum).to_proc.call # => array.rb:14:in `method': undefined method `sum' for class `Array' (NameError)
Run Code Online (Sandbox Code Playgroud)

这是预期的行为吗?有解决方法吗?

ruby proc refinements

5
推荐指数
1
解决办法
163
查看次数

Ruby改进了陷阱

在第2章" 改进 "部分的元编程Ruby 2中,我发现了以下Ruby代码:

class MyClass 
  def my_method
    "original my_method()"
  end

  def another_method 
    my_method
  end

end

module MyClassRefinement 
  refine MyClass do
    def my_method
      "refined my_method()"
    end 
  end
end

using MyClassRefinement
MyClass.new.my_method # => "refined my_method()"
MyClass.new.another_method # => "original my_method()" - How is this possible?
Run Code Online (Sandbox Code Playgroud)

据作者说:

但是,调用another_method 可能抓住你措手不及:即使你打电话another_methodusing,调用my_method本身发生之前using-所以它调用该方法的原始的,未精制的版本.

这完全让我失望.

为什么MyClass.new.another_method打印"原始my_method()",因为它使用后using MyClassRefinement,作者试图在这里说什么?

任何人都可以提供更直观/更好的解释吗?

谢谢.

ruby metaprogramming refinements

5
推荐指数
1
解决办法
132
查看次数

对块应用细化

假设我正在设计一种特定于领域的语言。对于这个简化的示例,我们有变量、数字以及将事物添加在一起的能力(变量或数字)

class Variable
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Addition
  attr_reader :lhs, :rhs

  def initialize(lhs, rhs)
    @lhs = lhs
    @rhs = rhs
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,如果我想表示表达式x + 1,我会写Addition.new(Variable.new('x'), 1)

我们可以通过+在 上提供一种方法来使这更方便Variable

class Variable
  def +(other)
    Addition.new(self, other)
  end
end
Run Code Online (Sandbox Code Playgroud)

然后我们就可以写了Variable.new('x') + 1

但现在,假设我想要相反的结果:1 + x。显然,我不想进行猴子补丁Integer#+,因为这会永久禁用普通的 Ruby 整数加法。我认为这将是一个很好的改进用例。

具体来说,我想定义一个方法expr,该方法采用一个块并在重新定义的上下文中评估该块+以构造我的 DSL 实例。也就是说,我想要类似的东西

module Context
  refine Integer do
    def +(other)
      Addition.new(self, other) …
Run Code Online (Sandbox Code Playgroud)

ruby dsl metaprogramming refinements

5
推荐指数
0
解决办法
168
查看次数