Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
201 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,4 +1,5 @@ | |||
*.gem | *.gem | ||
.bundle | .bundle | ||
*.swp | |||
Gemfile.lock | Gemfile.lock | ||
pkg/* | pkg/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
--color | |||
--backtrace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,5 +1,102 @@ | |||
require "its/version" | require "its/version" | ||
require "rspec/core" | |||
|
|
||
module Its | module Its | ||
# Your code goes here... | module ExampleGroupMethods | ||
|
|||
# Creates a nested example group named by the submitted +attribute+, | |||
# and then generates an example using the submitted block. | |||
# | |||
# # This ... | |||
# describe Array do | |||
# its(:size) { should eq(0) } | |||
# end | |||
# | |||
# # ... generates the same runtime structure as this: | |||
# describe Array do | |||
# describe "size" do | |||
# it "should eq(0)" do | |||
# subject.size.should eq(0) | |||
# end | |||
# end | |||
# end | |||
# | |||
# The attribute can be a +Symbol+ or a +String+. Given a +String+ | |||
# with dots, the result is as though you concatenated that +String+ | |||
# onto the subject in an expression. | |||
# | |||
# describe Person do | |||
# subject do | |||
# Person.new.tap do |person| | |||
# person.phone_numbers << "555-1212" | |||
# end | |||
# end | |||
# | |||
# its("phone_numbers.first") { should eq("555-1212") } | |||
# end | |||
# | |||
# When the subject is a +Hash+, you can refer to the Hash keys by | |||
# specifying a +Symbol+ or +String+ in an array. | |||
# | |||
# describe "a configuration Hash" do | |||
# subject do | |||
# { :max_users => 3, | |||
# 'admin' => :all_permissions } | |||
# end | |||
# | |||
# its([:max_users]) { should eq(3) } | |||
# its(['admin']) { should eq(:all_permissions) } | |||
# | |||
# # You can still access to its regular methods this way: | |||
# its(:keys) { should include(:max_users) } | |||
# its(:count) { should eq(2) } | |||
# end | |||
# | |||
# You can also pass any additional arguments the target method can accept: | |||
# | |||
# describe Person do | |||
# subject do | |||
# Person.new.tap do |person| | |||
# person.phone_numbers << "123-123" | |||
# person.phone_numbers << "234-234" | |||
# person.phone_numbers << "xxx-xxx" | |||
# end | |||
# end | |||
# | |||
# its("phone_numbers.first", 2) { should == ["123-123", "234-234"] | |||
# end | |||
# | |||
# | |||
# This is extraction for the RSpec Core. | |||
# For reference, see: | |||
# - https://github.com/rspec/rspec-core/blob/7ce078e4948e8f0d1745a50bb83dd87a68b2e50e/lib/rspec/core/subject.rb#L120 | |||
# This modifies the following behaviour: | |||
# - calls the target with arguments passed it | |||
# - changes the description to include the args (if any) | |||
def its(attribute, *args, &block) | |||
desc = attribute.to_s | |||
desc += "(#{args.map{|a| a.nil? ? 'nil' : a.to_s}.join(', ')})" unless args.empty? | |||
|
|||
describe(desc) do | |||
example do | |||
self.class.class_eval do | |||
define_method(:subject) do | |||
@_subject ||= if attribute.is_a?(Array) | |||
super()[*attribute] | |||
else | |||
attribute.to_s.split('.').inject(super()) do |target, method| | |||
target.send(method, *args) | |||
end | |||
end | |||
end | |||
end | |||
instance_eval(&block) | |||
end | |||
end | |||
end | |||
|
|||
end | |||
|
|||
end | end | ||
|
|||
RSpec::Core::ExampleGroup.send :extend, Its::ExampleGroupMethods |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,97 @@ | |||
require 'its' | |||
|
|||
describe "#its" do | |||
subject do | |||
Class.new do | |||
def initialize | |||
@call_count = 0 | |||
end | |||
|
|||
def call_count | |||
@call_count += 1 | |||
end | |||
end.new | |||
end | |||
|
|||
context "with a call counter" do | |||
its(:call_count) { should eq(1) } | |||
end | |||
|
|||
context "with nil value" do | |||
subject do | |||
Class.new do | |||
def nil_value | |||
nil | |||
end | |||
end.new | |||
end | |||
its(:nil_value) { should be_nil } | |||
end | |||
|
|||
context "with nested attributes" do | |||
subject do | |||
Class.new do | |||
def name | |||
"John" | |||
end | |||
end.new | |||
end | |||
its("name") { should eq("John") } | |||
its("name.size") { should eq(4) } | |||
its("name.size.class") { should eq(Fixnum) } | |||
end | |||
|
|||
context "when it responds to #[]" do | |||
subject do | |||
Class.new do | |||
def [](*objects) | |||
objects.map do |object| | |||
"#{object.class}: #{object.to_s}" | |||
end.join("; ") | |||
end | |||
|
|||
def name | |||
"George" | |||
end | |||
end.new | |||
end | |||
its([:a]) { should eq("Symbol: a") } | |||
its(['a']) { should eq("String: a") } | |||
its([:b, 'c', 4]) { should eq("Symbol: b; String: c; Fixnum: 4") } | |||
its(:name) { should eq("George") } | |||
context "when referring to an attribute without the proper array syntax" do | |||
context "it raises an error" do | |||
its(:age) do | |||
expect do | |||
should eq(64) | |||
end.to raise_error(NoMethodError) | |||
end | |||
end | |||
end | |||
end | |||
|
|||
context "when it does not respond to #[]" do | |||
subject { Object.new } | |||
|
|||
context "it raises an error" do | |||
its([:a]) do | |||
expect do | |||
should eq("Symbol: a") | |||
end.to raise_error(NoMethodError) | |||
end | |||
end | |||
end | |||
|
|||
context "with arguments passed in" do | |||
subject do | |||
Class.new do | |||
def currency(code) | |||
"$#{code}" | |||
end | |||
end.new | |||
end | |||
its(:currency, :us) { should eq("$us") } | |||
its(:currency, :uk) { should eq("$uk") } | |||
its(:currency, :ua) { should eq("$ua") } | |||
end | |||
end |