Skip to content

Commit

Permalink
implemented and tested
Browse files Browse the repository at this point in the history
  • Loading branch information
dnagir committed Jan 13, 2012
1 parent 4af2ca5 commit db45c7c
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
*.gem *.gem
.bundle .bundle
*.swp
Gemfile.lock Gemfile.lock
pkg/* pkg/*
2 changes: 2 additions & 0 deletions .rspec
@@ -0,0 +1,2 @@
--color
--backtrace
6 changes: 3 additions & 3 deletions its.gemspec
Expand Up @@ -18,7 +18,7 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"] s.require_paths = ["lib"]


# specify any dependencies here; for example: s.add_runtime_dependency "rspec-core", "~> 2.8"
# s.add_development_dependency "rspec" s.add_development_dependency "rspec-mocks"
# s.add_runtime_dependency "rest-client" s.add_development_dependency "rspec-expectations"
end end
99 changes: 98 additions & 1 deletion lib/its.rb
@@ -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
97 changes: 97 additions & 0 deletions spec/its_spec.rb
@@ -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

0 comments on commit db45c7c

Please sign in to comment.