schrodingers-cat 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ == 0.1.4
2
+
3
+ * Additionally switches to justools instead of core utilities
4
+
5
+ == 0.1.2
6
+
7
+ * Support for Rails > 3.1.1
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", "~> 2.11.0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", ">= 1.0.0"
12
+ gem "jeweler", "~> 1.8.4"
13
+ # gem "rcov", ">= 0"
14
+ gem 'i18n'
15
+ gem 'activesupport', '>= 3.1.0'
16
+ gem 'justools', '~> 1.1.8', :github => 'caleon/justools'
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ GIT
2
+ remote: git://github.com/caleon/justools.git
3
+ revision: 0f5215f4c6777fc96795924d62f4e2200602f5e3
4
+ specs:
5
+ justools (1.1.10)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activesupport (3.1.1)
11
+ multi_json (~> 1.0)
12
+ diff-lcs (1.1.3)
13
+ git (1.2.5)
14
+ i18n (0.6.1)
15
+ jeweler (1.8.4)
16
+ bundler (~> 1.0)
17
+ git (>= 1.2.5)
18
+ rake
19
+ rdoc
20
+ json (1.7.5)
21
+ multi_json (1.0.3)
22
+ rake (0.9.2.2)
23
+ rdoc (3.12)
24
+ json (~> 1.4)
25
+ rspec (2.11.0)
26
+ rspec-core (~> 2.11.0)
27
+ rspec-expectations (~> 2.11.0)
28
+ rspec-mocks (~> 2.11.0)
29
+ rspec-core (2.11.1)
30
+ rspec-expectations (2.11.3)
31
+ diff-lcs (~> 1.1.3)
32
+ rspec-mocks (2.11.3)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ activesupport (>= 3.1.0)
39
+ bundler (>= 1.0.0)
40
+ i18n
41
+ jeweler (~> 1.8.4)
42
+ justools (~> 1.1.8)!
43
+ rdoc (~> 3.12)
44
+ rspec (~> 2.11.0)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 caleon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,99 @@
1
+ = Schrodinger's Cat
2
+
3
+ == Usage:
4
+
5
+ gem 'schrodingers-cat'
6
+ # or with GitHub for latest:
7
+ gem 'schrodinger', :git => "git://github.com/caleon/schrodinger.git"
8
+
9
+ == Use case:
10
+
11
+ Able to avoid common patterns like:
12
+
13
+ user_or_id.is_a?(User) ? user_or_id.id : user_or_id
14
+
15
+ in favor of
16
+
17
+ user_or_id.if_a?(User).id # or
18
+ user_or_id.if_a?(User, :else => user_or_id).id
19
+ user_or_id.only_if_a?(User) || user_or_id
20
+
21
+ == Note:
22
+
23
+ These can't be overriden as they are not methods but low-level operators... ):
24
+
25
+ define_method(:"&&") {|obj| false }; define_method(:"||") {|obj| obj }
26
+
27
+ which means we can't reliably do something like
28
+
29
+ record.assuming_a(User).authentications.first || raise "You didn't supply a user with authentications!"
30
+
31
+ because if sc.is_a?(SchrodingersCat), we ideally want:
32
+
33
+ sc || false # => false
34
+ true && sc # => false
35
+
36
+ but instead, as || and && are low-level operators for short-circuiting, we get:
37
+
38
+ sc || false # => sc
39
+ true && sc # => sc
40
+
41
+ However, though normally nil is the only object which should respond to #nil? with a true, so does SchrodingersCat whose MODEL_OBJECT is nil.
42
+
43
+ == Examples:
44
+
45
+ === Example 1:
46
+
47
+ if user_or_id.is_a?(User) then do #id, else just return user_or_id
48
+
49
+ user_or_id = User.first
50
+ user_or_id.if_a?(User).id
51
+ => 1
52
+ user_or_id = User.first.id
53
+ user_or_id.if_a?(User).id
54
+ => 1
55
+
56
+
57
+ === Example 2:
58
+
59
+ Only if user_or_id.is_a?(User) run chained method normally. Otherwise, return nil on chained method call.
60
+
61
+ possible_match = "hello".match(/ello/)
62
+ possible_match.only_if_a?(MatchData)[0]
63
+ => "ello"
64
+ possible_match = "hello".match(/superman/)
65
+ possible_match.only_if_a?(MatchData)[0]
66
+ => nil
67
+
68
+
69
+ === Example 3:
70
+
71
+ If user_or_id.is_a?(User) continue with chain, else continue returning Schrodinger's Cat.
72
+
73
+ user_or_id = User.first
74
+ res = user_or_id.assuming_a(User).authentications.first.provider # assuming an authentications record exists.
75
+ => "facebook"
76
+ res.class
77
+ => String
78
+ user_or_id = User.find_by_email('nobody@juscribe.com') # if there is no user with that email,
79
+ res = user_or_id.assuming_a(User).authentications.first.provider
80
+ => nil
81
+ res.class
82
+ => SchrodingersCat
83
+
84
+
85
+ == Additional information
86
+
87
+ === Contributors
88
+
89
+ We have a short list of valued contributors. Check them all at:
90
+
91
+ http://github.com/caleon/schrodinger/contributors
92
+
93
+ === Maintainers
94
+
95
+ * caleon (http://github.com/caleon)
96
+
97
+ == License
98
+
99
+ MIT License. Copyright 2011-2012 caleon.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "schrodingers-cat"
18
+ gem.homepage = "http://github.com/caleon/schrodinger"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A convenience utility for dealing with the unknown state of an object's existence in order to avoid common code inelegance.}
21
+ gem.description = <<-DESC
22
+ The Schrodinger's Cat gem is a library that boasts neither novelty or
23
+ ingenuity, just the potential for writing more efficient code when it comes
24
+ to (and we've all been there) dealing with the ubiquitous cases wherein the
25
+ existence (or nil'ness) of the object referenced is ever in flux. To this
26
+ end, Schrodinger's Cat defines Object-level methods designed for theses
27
+ common cases.
28
+ DESC
29
+ gem.email = "caleon@gmail.com"
30
+ gem.authors = ["caleon"]
31
+ # dependencies defined in Gemfile
32
+ end
33
+ Jeweler::RubygemsDotOrgTasks.new
34
+
35
+ require 'rspec/core'
36
+ require 'rspec/core/rake_task'
37
+ RSpec::Core::RakeTask.new(:spec) do |spec|
38
+ spec.pattern = FileList['spec/**/*_spec.rb']
39
+ end
40
+
41
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
42
+ spec.pattern = 'spec/**/*_spec.rb'
43
+ spec.rcov = true
44
+ end
45
+
46
+ task :default => :spec
47
+
48
+ require 'rdoc/task'
49
+ Rake::RDocTask.new do |rdoc|
50
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "Schrodinger's Cat #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # require File.expand_path('../lib/schrodingers_cat', __FILE__)
2
+ require 'schrodinger'
@@ -0,0 +1,2 @@
1
+ # File exists only to resolve default library path lookup when name has dash.
2
+ require File.expand_path('../../schrodingers-cat', __FILE__)
@@ -0,0 +1,6 @@
1
+ require 'active_support/core_ext/module'
2
+ require 'active_support/core_ext/array/wrap'
3
+
4
+ require 'justools'
5
+ require 'schrodingers_cat/schrodingers_cat'
6
+ require 'schrodingers_cat/core_ext'
@@ -0,0 +1,88 @@
1
+ class Object
2
+ # if user_or_id.is_a?(User) then do #id, else just return user_or_id
3
+ # Ex: user_or_id = User.first
4
+ # user_or_id.if_a?(User).id
5
+ # => 1
6
+ # user_or_id = User.first.id
7
+ # user_or_id.if_a?(User).id
8
+ # => 1
9
+ def if_a?(*others, &block)
10
+ others.flatten_splat! # decide whether im using these or not. already using merge_options and shit.
11
+ opts = others.extract_options!
12
+ check_conditions = opts.key?(:conditions) ? opts.delete(:conditions) : send((opts.delete(:check) || :is_one_kind_of?), *others)
13
+ if opts.delete(:opposite) ? !check_conditions : check_conditions
14
+ block_given? ? yield(self) : self
15
+ else # :else => self is the default, for when i dont do any operations on original object.
16
+ opts.merge!(:else => self) unless opts.key?(:else) || opts[:chain] # if opts[:chain] is passed, then there is never an :else.
17
+ return opts[:else] if block_given? && opts.key?(:else)
18
+ SchrodingersCat.new(self, opts)
19
+ end
20
+ end
21
+
22
+ def unless_a?(*others, &block)
23
+ if_a?(*others.merge_options!(:opposite => true), &block)
24
+ end
25
+
26
+ # Only if user_or_id.is_a?(User) run chained method normally. Otherwise, return nil on chained method call.
27
+ # Ex: possible_match = "hello".match(/ello/)
28
+ # possible_match.only_if_a?(MatchData)[0]
29
+ # => "ello"
30
+ # possible_match = "hello".match(/superman/)
31
+ # possible_match.only_if_a?(MatchData)[0]
32
+ # => nil
33
+ def only_if_a?(*others, &block)
34
+ if_a?(*others.merge_options(:else => nil), &block)
35
+ end
36
+
37
+ def only_unless_a?(*others, &block)
38
+ only_if_a?(*others.merge_options(:opposite => true), &block)
39
+ end
40
+
41
+ # if user_or_id.is_a?(User) continue with chain, else continue returning Schrodinger's Cat.
42
+ # Ex: user_or_id = User.first
43
+ # res = user_or_id.assuming_a(User).authentications.first.provider # assuming an authentications record exists.
44
+ # => "facebook"
45
+ # res.class
46
+ # => String
47
+ # user_or_id = User.find_by_email('noone@kibblr.com') # if there is no user with ID=999,
48
+ # res = user_or_id.assuming_a(User).authentications.first.provider
49
+ # => nil
50
+ # res.class
51
+ # => SchrodingersCat
52
+ def assuming_a(*others, &block)
53
+ if_a?(*others.merge_options(:chain => true), &block)
54
+ end
55
+
56
+ ##################################
57
+ # Exact comparison of #== in is_one_of? rather than utilizing #=== in #is_one_kind_of
58
+ ###############################
59
+ def if_equals_a?(*others, &block); if_a?(*others.merge_options(:conditions => in?(others)), &block); end
60
+ def unless_equals_a?(*others, &block); if_equals_a?(*others.merge_options(:opposite => true), &block); end
61
+ def only_if_equals_a?(*others, &block); if_equals_a?(*others.merge_options(:else => nil), &block); end
62
+ def only_unless_equals_a?(*others, &block); unless_equals_a?(*others.merge_options(:else => nil), &block); end
63
+ def assuming_equals_a(*others, &block); if_equals_a?(*others.merge_options(:chain => true), &block); end
64
+
65
+ #########################
66
+ # Custom conditionals. ##
67
+ #########################
68
+ def if?(varied, *args, &block) if_a?(*args.merge_options(:conditions => resolve_conditions(varied)), &block); end
69
+ def unless?(*args, &block); if?(*args.merge_options(:opposite => true), &block); end
70
+ def only_if?(*args, &block); if?(*args.merge_options(:else => nil), &block); end
71
+ def only_unless?(*args, &block); only_if?(*args.merge_options(:opposite => true), &block); end
72
+ #def assuming(*args, &block); if?(*args.merge_options(:chain => true), &block); end
73
+
74
+ #########################
75
+ # Utilities ##
76
+ #########################
77
+ def present_else_nil; present_else(nil); end
78
+ def significant_else_nil; significant_else(nil); end
79
+
80
+ protected
81
+ def present_else(other); if?(:present?, :else => other) { self }; end
82
+ def significant_else(other); if?(:significant?, :else => other) { self }; end
83
+
84
+ private
85
+ def resolve_conditions(varied)
86
+ varied.is_a?(Symbol) ? __send__(varied) : varied.is_a?(Array) ? __send__(*varied) : varied.is_a?(String) ? varied =~ /^\./ ? __send__(:eval, "self#{varied}") : eval(varied) : !!varied
87
+ end
88
+ end
@@ -0,0 +1,7 @@
1
+ # Not used right now.
2
+ class Array
3
+ def compact_with_schrodinger
4
+ compact_without_schrodinger.reject(&:nil?)
5
+ end
6
+ alias_method_chain :compact, :schrodinger
7
+ end
@@ -0,0 +1,56 @@
1
+ class SchrodingersCat
2
+ #######################
3
+ ## Schrodinger's Cat ##
4
+ #######################
5
+ #
6
+ # Able to avoid shit like: user_or_id.is_a?(User) ? user_or_id.id : user_or_id
7
+ # in favor of user_or_id.if_a?(User).id
8
+ # or user_or_id.if_a?(User, :else => user_or_id).id
9
+ # or user_or_id.only_if_a?(User) || user_or_id
10
+
11
+ #####################
12
+ ## Note: ##
13
+ #####################
14
+ # These can't be overriden as they are not methods but low-level operators... ):
15
+ # define_method(:"&&") {|obj| false }; define_method(:"||") {|obj| obj }
16
+ # which means I can't reliably do something like record.assuming_a(User).authentications.first || raise "You didn't supply a user with authentications!"
17
+ # because if sc.is_a?(SchrodingersCat), we ideally want:
18
+ # sc || false # => false
19
+ # true && sc # => false
20
+ # but instead, as || and && are low-level operators for short-circuiting, we get:
21
+ # sc || false # => sc
22
+ # true && sc # => sc
23
+ # However, though normally nil is the only object which should respond to #nil? with a true, so does SchrodingersCat whose MODEL_OBJECT is nil.
24
+ attr_accessor :original, :method_chain, :else
25
+ unless const_defined?(:MODEL_OBJECT)
26
+ SchrodingersCat.const_set(:MODEL_OBJECT, nil)
27
+ end
28
+
29
+ def initialize(original, attrs={})
30
+ self.original, self.method_chain = original, Array.wrap(attrs[:method_chain])
31
+ self.else, @_else_set = attrs[:else], true if attrs.key?(:else)
32
+ end
33
+
34
+ [ 'inspect', 'to_s', 'to_i', 'nil?', 'empty?' ,'blank?' ].each do |meth|
35
+ class_eval %{ def #{meth}; MODEL_OBJECT.#{meth}; end; }
36
+ end
37
+ #delegate *[ 'inspect', 'to_s', 'to_i', 'nil?', 'empty?' ,'blank?' ].map(&:intern), :to => :MODEL_OBJECT
38
+
39
+ # if Rails.env.development?
40
+ # def inspect; "nil (SchrodingersCat)"; end
41
+ # end
42
+
43
+ [ "==", "eql?", "&", "^", "|" ].each do |meth|
44
+ class_eval %{ def #{meth}(other); MODEL_OBJECT.#{meth}(other); end; }
45
+ end
46
+ #delegate *[ "==", "eql?", "&", "^", "|" ].map(&:intern), :to => :MODEL_OBJECT
47
+
48
+ def dup; nil; end
49
+
50
+ def method_missing(method_sym, *arguments, &block)
51
+ return self.else if @_else_set
52
+ self.method_chain << { method_sym => arguments.push(&block) }
53
+ self
54
+ end
55
+ private :method_missing
56
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :schrodinger do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,346 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Schrodinger's Cat" do
4
+
5
+ specify 'SchrodingersCat class should be defined' do
6
+ defined?(SchrodingersCat).should be_true
7
+ end
8
+
9
+ # describe Array do
10
+ # it { should respond_to :compact_with_schrodinger }
11
+ # end
12
+
13
+ describe SchrodingersCat do
14
+ let(:original) { mock('original') }
15
+ subject(:cat) { described_class.new(original) }
16
+
17
+ it 'is modeled after nil' do
18
+ described_class::MODEL_OBJECT.should be_nil
19
+ end
20
+
21
+ its(:dup) { should be_nil }
22
+ end
23
+
24
+ describe Object do
25
+ before(:each) do
26
+ subject.stub(:do_something => :result)
27
+ end
28
+
29
+ describe 'Basic responses' do
30
+ %w(if_a? unless_a? only_if_a? only_unless_a? assuming_a if_equals_a?
31
+ unless_equals_a? only_if_equals_a? only_unless_equals_a?
32
+ assuming_equals_a if? unless? only_if? only_unless?).each do |meth|
33
+ it { should respond_to meth.to_sym }
34
+ end
35
+ end
36
+
37
+ describe '#if_a?' do
38
+ it 'returns self for false check' do
39
+ subject.if_a?(Numeric).do_something.should be subject
40
+ end
41
+
42
+ it 'calls chained method for true check' do
43
+ subject.if_a?(Object).do_something.should == :result
44
+ end
45
+
46
+ it 'returns evaluated block for true check' do
47
+ subject.if_a?(Object) { |o| o.do_something }.should == :result
48
+ end
49
+
50
+ context 'with custom :conditions' do
51
+ it 'evaluates uses :conditions for truth check' do
52
+ subject.if_a?(Numeric, :conditions => true).do_something.should == :result
53
+ subject.if_a?(Numeric, :conditions => false).do_something.should be subject
54
+ end
55
+ end
56
+
57
+ context 'with custom :check requested' do
58
+ it 'calls the :check method instead of :is_one_kind_of?' do
59
+ subject.should_receive(:some_check).with(Numeric)
60
+ subject.if_a?(Numeric, :check => :some_check)
61
+ end
62
+ end
63
+
64
+ context 'with :opposite conditions requested' do
65
+
66
+ it 'returns self for true check' do
67
+ subject.if_a?(Object, :opposite => true).do_something.should be subject
68
+ end
69
+
70
+ it 'calls chained method for false check' do
71
+ subject.if_a?(Numeric, :opposite => true).do_something.should == :result
72
+ end
73
+
74
+ it 'returns evaluated block for false check' do
75
+ subject.if_a?(Numeric, :opposite => true) { |o| o.do_something }.should == :result
76
+ end
77
+ end
78
+
79
+ context 'with custom :else provided' do
80
+
81
+ it 'returns self for true check' do
82
+ subject.if_a?(Object, :else => :something_else).do_something.should == :result
83
+ end
84
+
85
+ it 'returns else for false check' do
86
+ subject.if_a?(Numeric, :else => :something_else).do_something.should == :something_else
87
+ end
88
+ end
89
+
90
+ context 'with custom :chain provided' do
91
+
92
+ it 'returns a SchrodingersCat' do
93
+ subject.if_a?(Numeric, :chain => true).do_something.should be_a SchrodingersCat
94
+ end
95
+ end
96
+ end
97
+
98
+ describe '#unless_a?' do
99
+ it 'simply calls #if_a? with :opposite => true' do
100
+ subject.should_receive(:if_a?).with(Numeric, hash_including(:opposite => true))
101
+ subject.unless_a?(Numeric)
102
+ end
103
+ end
104
+
105
+ describe '#only_if_a?' do
106
+ it 'simply calls #if_a? with :else => nil' do
107
+ subject.should_receive(:if_a?).with(Numeric, hash_including(:else => nil))
108
+ subject.only_if_a?(Numeric)
109
+ end
110
+ end
111
+
112
+ describe '#only_unless_a?' do
113
+ it 'simply calls #only_if_a? with :opposite => true' do
114
+ subject.should_receive(:only_if_a?).with(Numeric, hash_including(:opposite => true))
115
+ subject.only_unless_a?(Numeric)
116
+ end
117
+ end
118
+
119
+ describe '#assuming_a' do
120
+ it 'simply calls #if_a? with :chain => true' do
121
+ subject.should_receive(:if_a?).with(Numeric, hash_including(:chain => true))
122
+ subject.assuming_a(Numeric)
123
+ end
124
+ end
125
+
126
+ describe '#if_equals_a?' do
127
+ it 'simply calls #if_a? with :check => :is_included_in?' do
128
+ subject.should_receive(:if_a?).with(Numeric, hash_including(:conditions))
129
+ subject.if_equals_a?(Numeric)
130
+ end
131
+ end
132
+
133
+ describe '#unless_equals_a?' do
134
+ it 'simply calls #if_equals_a? with :opposite => true' do
135
+ subject.should_receive(:if_equals_a?).with(Numeric, hash_including(:opposite => true))
136
+ subject.unless_equals_a?(Numeric)
137
+ end
138
+ end
139
+
140
+ describe '#only_if_equals_a?' do
141
+ it 'simply calls #if_equals_a? with :else => nil' do
142
+ subject.should_receive(:if_equals_a?).with(Numeric, hash_including(:else => nil))
143
+ subject.only_if_equals_a?(Numeric)
144
+ end
145
+ end
146
+
147
+ describe '#only_unless_equals_a?' do
148
+ it 'simply calls #unless_equals_a? with :else => nil' do
149
+ subject.should_receive(:unless_equals_a?).with(Numeric, hash_including(:else => nil))
150
+ subject.only_unless_equals_a?(Numeric)
151
+ end
152
+ end
153
+
154
+ describe '#assuming_equals_a' do
155
+ it 'simply calls #if_equals_a? with :chain => true' do
156
+ subject.should_receive(:if_equals_a?).with(Numeric, hash_including(:chain => true))
157
+ subject.assuming_equals_a(Numeric)
158
+ end
159
+ end
160
+
161
+ describe '#if?' do
162
+ it 'simply calls #if_a? with :conditions => something' do
163
+ Object.any_instance.stub(:resolve_conditions => :resolved_conditions)
164
+ subject.should_receive(:if_a?).with(hash_including(:conditions => :resolved_conditions))
165
+ subject.if?(:varied)
166
+ end
167
+ end
168
+
169
+ describe '#unless?' do
170
+ it 'simply calls #if? with :opposite => true' do
171
+ subject.should_receive(:if?).with(:varied, hash_including(:opposite => true))
172
+ subject.unless?(:varied)
173
+ end
174
+ end
175
+
176
+ describe '#only_if?' do
177
+ it 'simply calls #if? with :else => nil' do
178
+ subject.should_receive(:if?).with(:varied, hash_including(:else => nil))
179
+ subject.only_if?(:varied)
180
+ end
181
+ end
182
+
183
+ describe '#only_unless?' do
184
+ it 'simply calls #only_if? with :opposite => true' do
185
+ subject.should_receive(:only_if?).with(:varied, hash_including(:opposite => true))
186
+ subject.only_unless?(:varied)
187
+ end
188
+ end
189
+ end # / describe Object
190
+
191
+ describe 'Real world examples' do
192
+ let(:hash) { { :a => 3 } }
193
+
194
+ describe '#if_a?' do
195
+
196
+ it 'checks false and returns self despite method' do
197
+ hash.if_a?(Numeric).keys.should == hash
198
+ end
199
+
200
+ it 'checks true and calls the chained method' do
201
+ hash.if_a?(Hash).keys.should == [:a]
202
+ end
203
+
204
+ it 'checks true and returns the result of block' do
205
+ hash.if_a?(Hash) { |h| h.keys }.should == [:a]
206
+ end
207
+ end
208
+
209
+ describe '#unless_a?' do
210
+
211
+ it 'checks false and returns self despite method' do
212
+ hash.unless_a?(Hash).keys.should == hash
213
+ end
214
+
215
+ it 'checks true and calls the chained method' do
216
+ hash.unless_a?(Numeric).keys.should == [:a]
217
+ end
218
+
219
+ it 'checks true and returns the result of block' do
220
+ hash.unless_a?(Numeric) { |h| h.keys }.should == [:a]
221
+ end
222
+ end
223
+
224
+ describe '#only_if_a?' do
225
+
226
+ it 'checks false and returns nil' do
227
+ hash.only_if_a?(String).to_sym.should be_nil
228
+ end
229
+
230
+ it 'checks true and calls the method' do
231
+ hash.only_if_a?(Hash).keys.should == [:a]
232
+ end
233
+ end
234
+
235
+ describe '#only_unless_a?' do
236
+
237
+ it 'checks false and returns nil' do
238
+ hash.only_unless_a?(Hash).to_sym.should be_nil
239
+ end
240
+
241
+ it 'checks true and calls the method' do
242
+ hash.only_unless_a?(String).keys.should == [:a]
243
+ end
244
+ end
245
+
246
+ describe '#assuming_a' do
247
+
248
+ it 'allows chaining of methods without error even if check was false' do
249
+ expect { hash.assuming_a(String).upcase.capitalize.downcase
250
+ }.not_to raise_error
251
+ end
252
+
253
+ it 'returns a SchrodingersCat if check was false' do
254
+ result = hash.assuming_a(String).upcase.capitalize.downcase
255
+ result.should be_a SchrodingersCat
256
+ result.inspect.should == 'nil'
257
+ end
258
+ end
259
+
260
+ describe '#if_equals_a?' do
261
+
262
+ it 'checks false and returns self' do
263
+ hash.if_equals_a?({ 'a' => 4 }).keys.should be hash
264
+ 3.if_equals_a?(4).keys.should == 3
265
+ end
266
+
267
+ it 'checks true and calls the method' do
268
+ # hash.if_equals_a?({ 'a' => 4 }, { :a => 4 }).keys.should == [:a] # FIXME: merging options assumes the latest of arguments is not an arg but an option...
269
+ 3.if_equals_a?(0, 3).succ.should == 4
270
+ end
271
+ end
272
+
273
+ describe '#unless_equals_a?' do
274
+
275
+ it 'checks false and returns self' do
276
+ 3.unless_equals_a?(3).keys.should == 3
277
+ end
278
+
279
+ it 'checks true and calls the method' do
280
+ 3.unless_equals_a?(0, 1).succ.should == 4
281
+ end
282
+ end
283
+
284
+ describe '#only_if_equals_a?' do
285
+
286
+ it 'checks false and returns nil' do
287
+ 3.only_if_equals_a?(4).keys.should be_nil
288
+ end
289
+
290
+ it 'checks true and calls the method' do
291
+ 3.only_if_equals_a?(1, 2, 3).succ.should == 4
292
+ end
293
+ end
294
+
295
+ describe '#only_unless_equals_a?' do
296
+
297
+ it 'checks false and returns nil' do
298
+ 3.only_unless_equals_a?(3, 4).keys.should be_nil
299
+ end
300
+
301
+ it 'checks true and calls the method' do
302
+ 3.only_unless_equals_a?(1, 2).succ.should == 4
303
+ end
304
+ end
305
+
306
+ describe '#assuming_equals_a' do
307
+
308
+ it 'checks false and returns SchrodingersCat' do
309
+ 3.assuming_equals_a(4).succ.succ.succ.should be_a SchrodingersCat
310
+ end
311
+
312
+ it 'checks true and calls the chained methods' do
313
+ 3.assuming_equals_a(3).succ.succ.succ.should == 6
314
+ end
315
+ end
316
+
317
+ describe '#if?' do
318
+
319
+ it 'checks custom predicate symbol' do
320
+ 3.if?(:odd?).succ.should == 4
321
+ 3.if?(:even?).succ.should == 3
322
+ end
323
+
324
+ it 'checks custom predicate symbol with a method' do
325
+ 3.if?([:is_a?, Numeric]).succ.should == 4
326
+ 3.if?([:is_a?, Array]).first.should == 3
327
+ end
328
+
329
+ it 'checks the return of sending receiver an arbitrary method supplied as String beginning with a period' do
330
+ 3.if?('.succ.even?').succ.should == 4
331
+ 3.if?('.succ.odd?').succ.should == 3
332
+ end
333
+
334
+ it 'checks the return of arbitrary method supplied as String' do
335
+ 3.if?('Date.new.is_a?(Date)').succ.should == 4
336
+ 3.if?('Date.new.is_a?(String)').succ.should == 3
337
+ end
338
+ end
339
+
340
+ # No need to belabor the point. You get it, right?
341
+ # describe '#unless?'
342
+ # describe '#only_if?'
343
+ # describe '#only_unless?'
344
+ end
345
+
346
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'schrodingers-cat'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ config.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
12
+ end
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schrodingers-cat
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - caleon
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-10-22 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ hash: 35
27
+ segments:
28
+ - 2
29
+ - 11
30
+ - 0
31
+ version: 2.11.0
32
+ prerelease: false
33
+ type: :development
34
+ name: rspec
35
+ requirement: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ hash: 31
43
+ segments:
44
+ - 3
45
+ - 12
46
+ version: "3.12"
47
+ prerelease: false
48
+ type: :development
49
+ name: rdoc
50
+ requirement: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ version_requirements: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 23
58
+ segments:
59
+ - 1
60
+ - 0
61
+ - 0
62
+ version: 1.0.0
63
+ prerelease: false
64
+ type: :development
65
+ name: bundler
66
+ requirement: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ version_requirements: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ hash: 63
74
+ segments:
75
+ - 1
76
+ - 8
77
+ - 4
78
+ version: 1.8.4
79
+ prerelease: false
80
+ type: :development
81
+ name: jeweler
82
+ requirement: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ version_requirements: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ prerelease: false
94
+ type: :development
95
+ name: i18n
96
+ requirement: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ version_requirements: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 3
106
+ - 1
107
+ - 0
108
+ version: 3.1.0
109
+ prerelease: false
110
+ type: :development
111
+ name: activesupport
112
+ requirement: *id006
113
+ - !ruby/object:Gem::Dependency
114
+ version_requirements: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ~>
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 1
122
+ - 1
123
+ - 8
124
+ version: 1.1.8
125
+ prerelease: false
126
+ type: :development
127
+ name: justools
128
+ requirement: *id007
129
+ description: " The Schrodinger's Cat gem is a library that boasts neither novelty or\n ingenuity, just the potential for writing more efficient code when it comes\n to (and we've all been there) dealing with the ubiquitous cases wherein the\n existence (or nil'ness) of the object referenced is ever in flux. To this\n end, Schrodinger's Cat defines Object-level methods designed for theses\n common cases.\n"
130
+ email: caleon@gmail.com
131
+ executables: []
132
+
133
+ extensions: []
134
+
135
+ extra_rdoc_files:
136
+ - LICENSE
137
+ - README.rdoc
138
+ files:
139
+ - .document
140
+ - .rspec
141
+ - CHANGELOG.rdoc
142
+ - Gemfile
143
+ - Gemfile.lock
144
+ - LICENSE
145
+ - README.rdoc
146
+ - Rakefile
147
+ - VERSION
148
+ - init.rb
149
+ - lib/schrodingers-cat.rb
150
+ - lib/schrodingers/cat.rb
151
+ - lib/schrodingers_cat/core_ext.rb
152
+ - lib/schrodingers_cat/dependencies.rb
153
+ - lib/schrodingers_cat/schrodingers_cat.rb
154
+ - lib/tasks/schrodinger_tasks.rake
155
+ - spec/schrodingers-cat_spec.rb
156
+ - spec/spec_helper.rb
157
+ homepage: http://github.com/caleon/schrodinger
158
+ licenses:
159
+ - MIT
160
+ post_install_message:
161
+ rdoc_options: []
162
+
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ hash: 3
171
+ segments:
172
+ - 0
173
+ version: "0"
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ none: false
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ hash: 3
180
+ segments:
181
+ - 0
182
+ version: "0"
183
+ requirements: []
184
+
185
+ rubyforge_project:
186
+ rubygems_version: 1.8.24
187
+ signing_key:
188
+ specification_version: 3
189
+ summary: A convenience utility for dealing with the unknown state of an object's existence in order to avoid common code inelegance.
190
+ test_files: []
191
+