schrodingers-cat 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/CHANGELOG.rdoc +7 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +44 -0
- data/LICENSE +20 -0
- data/README.rdoc +99 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/init.rb +2 -0
- data/lib/schrodingers/cat.rb +2 -0
- data/lib/schrodingers-cat.rb +6 -0
- data/lib/schrodingers_cat/core_ext.rb +88 -0
- data/lib/schrodingers_cat/dependencies.rb +7 -0
- data/lib/schrodingers_cat/schrodingers_cat.rb +56 -0
- data/lib/tasks/schrodinger_tasks.rake +4 -0
- data/spec/schrodingers-cat_spec.rb +346 -0
- data/spec/spec_helper.rb +12 -0
- metadata +191 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/CHANGELOG.rdoc
ADDED
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,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,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,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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
+
|