Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions spec/ruby/core/proc/fixtures/refined.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,31 @@ def quiet
end
end
end

# Refines operators and element access, including Hash#[] with a String
# key, so specs can check the specialized call paths implementations use
# for them.
module Operators
refine Integer do
def +(other)
"plus(#{self},#{other})"
end

def <(other)
"lt"
end
end

refine Array do
def [](i)
"at#{i}"
end
end

refine Hash do
def [](k)
"aref(#{k})"
end
end
end
end
62 changes: 62 additions & 0 deletions spec/ruby/core/proc/refined_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@
pr.should_not.lambda?
end

it "preserves the class of a Proc subclass instance" do
subclass = Class.new(Proc)
refined = subclass.new { |s| s.shout }.refined(ProcRefinedSpecs::StringShout)
refined.should.instance_of?(subclass)
refined.call("hi").should == "HI!"
end

it "does not copy singleton methods of the receiver" do
pr = -> s { s.shout }
def pr.tag; :orig; end
refined = pr.refined(ProcRefinedSpecs::StringShout)
refined.should_not.respond_to?(:tag)
refined.call("hi").should == "HI!"
end

it "keeps the refinements active in blocks nested inside the body" do
pr = -> a { a.map { |s| s.shout } }
pr.refined(ProcRefinedSpecs::StringShout).call(%w[a b]).should == ["A!", "B!"]
Expand All @@ -63,6 +78,45 @@ def obj.shout_hi
pr.refined(ProcRefinedSpecs::StringShout).call.should == "HI!"
end

it "keeps the refinements active in instance methods defined inside the body" do
pr = -> {
Class.new {
def shout_hi
"hi".shout
end
}.new.shout_hi
}
pr.refined(ProcRefinedSpecs::StringShout).call.should == "HI!"
end

it "keeps the refinements active in a class body opened with the class keyword inside the body" do
pr = -> {
class ProcRefinedSpecs::ClassBody
def shout_hi
"hi".shout
end
end
ProcRefinedSpecs::ClassBody.new.shout_hi
}
pr.refined(ProcRefinedSpecs::StringShout).call.should == "HI!"
ensure
ProcRefinedSpecs.send(:remove_const, :ClassBody) if ProcRefinedSpecs.const_defined?(:ClassBody)
end

it "applies the refinements to Symbol#to_proc blocks created inside the body" do
pr = -> a { a.map(&:shout) }
pr.refined(ProcRefinedSpecs::StringShout).call(%w[a b]).should == ["A!", "B!"]
-> { pr.call(%w[a b]) }.should.raise(NoMethodError)
end

it "applies the refinements to operators and element access" do
refined = -> a, b { [a + b, a < b] }.refined(ProcRefinedSpecs::Operators)
refined.call(1, 2).should == ["plus(1,2)", "lt"]
-> a { a[0] }.refined(ProcRefinedSpecs::Operators).call([9]).should == "at0"
-> h { h["x"] }.refined(ProcRefinedSpecs::Operators).call({ "x" => 1 }).should == "aref(x)"
-> a, b { a + b }.call(1, 2).should == 3
end

it "keeps the refinements active when called via instance_eval, instance_exec and class_eval" do
pr = proc { "hi".shout }
refined = pr.refined(ProcRefinedSpecs::StringShout)
Expand Down Expand Up @@ -111,5 +165,13 @@ def obj.shout_hi
refined = pr.refined(ProcRefinedSpecs::StringShout)
-> { Module.new.module_eval(&refined) }.should.raise(RuntimeError)
end

it "allows calling refine inside the body" do
pr = -> s {
Module.new { refine(String) { def whisper; downcase; end } }
s.shout
}
pr.refined(ProcRefinedSpecs::StringShout).call("hi").should == "HI!"
end
end
end