naught 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +2 -0
  4. data/Changelog.md +6 -0
  5. data/Gemfile +1 -0
  6. data/Guardfile +10 -0
  7. data/README.markdown +413 -0
  8. data/Rakefile +5 -0
  9. data/lib/naught.rb +1 -4
  10. data/lib/naught/null_class_builder.rb +37 -137
  11. data/lib/naught/null_class_builder/command.rb +20 -0
  12. data/lib/naught/null_class_builder/commands.rb +8 -0
  13. data/lib/naught/null_class_builder/commands/define_explicit_conversions.rb +13 -24
  14. data/lib/naught/null_class_builder/commands/define_implicit_conversions.rb +14 -0
  15. data/lib/naught/null_class_builder/commands/impersonate.rb +9 -0
  16. data/lib/naught/null_class_builder/commands/mimic.rb +40 -0
  17. data/lib/naught/null_class_builder/commands/pebble.rb +36 -0
  18. data/lib/naught/null_class_builder/commands/predicates_return.rb +47 -0
  19. data/lib/naught/null_class_builder/commands/singleton.rb +24 -0
  20. data/lib/naught/null_class_builder/commands/traceable.rb +19 -0
  21. data/lib/naught/null_class_builder/conversions_module.rb +57 -0
  22. data/lib/naught/version.rb +1 -1
  23. data/naught.gemspec +2 -1
  24. data/spec/base_object_spec.rb +47 -0
  25. data/spec/basic_null_object_spec.rb +35 -0
  26. data/spec/blackhole_spec.rb +16 -0
  27. data/spec/conversions_spec.rb +20 -0
  28. data/spec/functions/actual_spec.rb +22 -0
  29. data/spec/functions/just_spec.rb +22 -0
  30. data/spec/functions/maybe_spec.rb +35 -0
  31. data/spec/functions/null_spec.rb +34 -0
  32. data/spec/implicit_conversions_spec.rb +25 -0
  33. data/spec/mimic_spec.rb +122 -0
  34. data/spec/naught/null_object_builder/command_spec.rb +10 -0
  35. data/spec/naught/null_object_builder_spec.rb +31 -0
  36. data/spec/naught_spec.rb +77 -411
  37. data/spec/pebble_spec.rb +75 -0
  38. data/spec/predicate_spec.rb +80 -0
  39. data/spec/singleton_null_object_spec.rb +35 -0
  40. data/spec/spec_helper.rb +13 -1
  41. data/spec/support/convertable_null.rb +4 -0
  42. metadata +76 -32
  43. data/.rspec +0 -1
  44. data/README.org +0 -340
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'stringio'
3
+
4
+ describe 'pebble null object' do
5
+ class Caller
6
+ def call_method(thing)
7
+ thing.info
8
+ end
9
+
10
+ def call_method_inside_block(thing)
11
+ 2.times.each { thing.info }
12
+ end
13
+
14
+ def call_method_inside_nested_block(thing)
15
+ 2.times.each { 2.times.each { thing.info } }
16
+ end
17
+ end
18
+
19
+ subject(:null) { null_class.new }
20
+ let(:null_class) {
21
+ output = test_output # getting local binding
22
+ Naught.build do |b|
23
+ b.pebble output
24
+ end
25
+ }
26
+
27
+ let(:test_output) { StringIO.new }
28
+
29
+ it 'prints the name of the method called' do
30
+ expect(test_output).to receive(:puts).with(/^info\(\)/)
31
+ null.info
32
+ end
33
+
34
+ it 'prints the arguments received' do
35
+ expect(test_output).to receive(:puts).with(/^info\(\'foo\', 5, \:sym\)/)
36
+ null.info("foo", 5, :sym)
37
+ end
38
+
39
+ it 'prints the name of the caller' do
40
+ expect(test_output).to receive(:puts).with(/from call_method$/)
41
+ Caller.new.call_method(null)
42
+ end
43
+
44
+ it 'returns self' do
45
+ expect(null.info).to be(null)
46
+ end
47
+
48
+ context "when is called from a block" do
49
+ it "prints the indication of a block" do
50
+ expect(test_output).to receive(:puts).twice.
51
+ with(/from block/)
52
+ Caller.new.call_method_inside_block(null)
53
+ end
54
+
55
+ it "prints the name of the method that has the block" do
56
+ expect(test_output).to receive(:puts).twice.
57
+ with(/in call_method_inside_block$/)
58
+ Caller.new.call_method_inside_block(null)
59
+ end
60
+ end
61
+
62
+ context "when is called from many levels blocks" do
63
+ it "prints the indication of blocks and its levels" do
64
+ expect(test_output).to receive(:puts).exactly(4).times.
65
+ with(/from block \(2 levels\)/)
66
+ Caller.new.call_method_inside_nested_block(null)
67
+ end
68
+
69
+ it "prints the name of the method that has the block" do
70
+ expect(test_output).to receive(:puts).exactly(4).times.
71
+ with(/in call_method_inside_nested_block$/)
72
+ Caller.new.call_method_inside_nested_block(null)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'a null object with predicates_return(false)' do
4
+ subject(:null) { null_class.new }
5
+ let(:null_class) {
6
+ Naught.build do |config|
7
+ config.predicates_return false
8
+ end
9
+ }
10
+
11
+ it 'responds to predicate-style methods with false' do
12
+ expect(null.too_much_coffee?).to eq(false)
13
+ end
14
+
15
+ it 'responds to other methods with nil' do
16
+ expect(null.foobar).to eq(nil)
17
+ end
18
+
19
+ describe '(black hole)' do
20
+ let(:null_class) {
21
+ Naught.build do |config|
22
+ config.black_hole
23
+ config.predicates_return false
24
+ end
25
+ }
26
+
27
+ it 'responds to predicate-style methods with false' do
28
+ expect(null.too_much_coffee?).to eq(false)
29
+ end
30
+
31
+ it 'responds to other methods with self' do
32
+ expect(null.foobar).to be(null)
33
+ end
34
+ end
35
+
36
+ describe '(black hole, reverse order config)' do
37
+ let(:null_class) {
38
+ Naught.build do |config|
39
+ config.predicates_return false
40
+ config.black_hole
41
+ end
42
+ }
43
+
44
+ it 'responds to predicate-style methods with false' do
45
+ expect(null.too_much_coffee?).to eq(false)
46
+ end
47
+
48
+ it 'responds to other methods with self' do
49
+ expect(null.foobar).to be(null)
50
+ end
51
+ end
52
+
53
+
54
+ class Coffee
55
+ def black?; true; end
56
+ def origin; "Ethiopia"; end
57
+ end
58
+
59
+ describe '(mimic)' do
60
+ let(:null_class) {
61
+ Naught.build do |config|
62
+ config.mimic Coffee
63
+ config.predicates_return false
64
+ end
65
+ }
66
+
67
+ it 'responds to predicate-style methods with false' do
68
+ expect(null.black?).to eq(false)
69
+ end
70
+
71
+ it 'responds to other methods with nil' do
72
+ expect(null.origin).to be(nil)
73
+ end
74
+
75
+ it 'does not respond to undefined methods' do
76
+ expect(null).not_to respond_to(:leaf_variety)
77
+ expect{null.leaf_variety}.to raise_error(NoMethodError)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'singleton null object' do
4
+ subject(:null_class) {
5
+ Naught.build do |b|
6
+ b.singleton
7
+ end
8
+ }
9
+
10
+ it 'does not respond to .new' do
11
+ expect{ null_class.new }.to raise_error
12
+ end
13
+
14
+ it 'has only one instance' do
15
+ null1 = null_class.instance
16
+ null2 = null_class.instance
17
+ expect(null1).to be(null2)
18
+ end
19
+
20
+ it 'can be cloned' do
21
+ null = null_class.instance
22
+ expect(null.clone).to be(null)
23
+ end
24
+
25
+ it 'can be duplicated' do
26
+ null = null_class.instance
27
+ expect(null.dup).to be(null)
28
+ end
29
+ it 'aliases .instance to .get' do
30
+ expect(null_class.get).to be null_class.instance
31
+ end
32
+ it 'permits arbitrary arguments to be passed to .get' do
33
+ null_class.get(42, foo: "bar")
34
+ end
35
+ end
@@ -1 +1,13 @@
1
- $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
1
+ GEM_ROOT = File.expand_path("../../", __FILE__)
2
+ $:.unshift File.join(GEM_ROOT, "lib")
3
+
4
+ if ENV["TRAVIS"]
5
+ require 'coveralls'
6
+ Coveralls.wear!
7
+ else
8
+ require 'simplecov'
9
+ SimpleCov.start
10
+ end
11
+
12
+ require 'naught'
13
+ Dir[File.join(GEM_ROOT, "spec", "support", "**/*.rb")].each { |f| require f }
@@ -0,0 +1,4 @@
1
+ ConvertableNull = Naught.build do |b|
2
+ b.null_equivalents << ""
3
+ b.traceable
4
+ end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: naught
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - Avdi Grimm
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-05-29 00:00:00.000000000 Z
11
+ date: 2013-11-08 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,65 +27,71 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ~>
52
46
  - !ruby/object:Gem::Version
53
- version: '0'
47
+ version: '2.14'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ~>
60
53
  - !ruby/object:Gem::Version
61
- version: '0'
54
+ version: '2.14'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: guard
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: guard-rspec
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
84
88
  - !ruby/object:Gem::Version
85
89
  version: '0'
86
90
  type: :development
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
- - - ! '>='
94
+ - - '>='
92
95
  - !ruby/object:Gem::Version
93
96
  version: '0'
94
97
  description: Naught is a toolkit for building Null Objects
@@ -99,45 +102,86 @@ extensions: []
99
102
  extra_rdoc_files: []
100
103
  files:
101
104
  - .gitignore
102
- - .rspec
105
+ - .travis.yml
106
+ - Changelog.md
103
107
  - Gemfile
104
108
  - Guardfile
105
109
  - LICENSE.txt
106
- - README.org
110
+ - README.markdown
107
111
  - Rakefile
108
112
  - lib/naught.rb
109
113
  - lib/naught/null_class_builder.rb
114
+ - lib/naught/null_class_builder/command.rb
115
+ - lib/naught/null_class_builder/commands.rb
110
116
  - lib/naught/null_class_builder/commands/define_explicit_conversions.rb
117
+ - lib/naught/null_class_builder/commands/define_implicit_conversions.rb
118
+ - lib/naught/null_class_builder/commands/impersonate.rb
119
+ - lib/naught/null_class_builder/commands/mimic.rb
120
+ - lib/naught/null_class_builder/commands/pebble.rb
121
+ - lib/naught/null_class_builder/commands/predicates_return.rb
122
+ - lib/naught/null_class_builder/commands/singleton.rb
123
+ - lib/naught/null_class_builder/commands/traceable.rb
124
+ - lib/naught/null_class_builder/conversions_module.rb
111
125
  - lib/naught/version.rb
112
126
  - naught.gemspec
127
+ - spec/base_object_spec.rb
128
+ - spec/basic_null_object_spec.rb
129
+ - spec/blackhole_spec.rb
130
+ - spec/conversions_spec.rb
131
+ - spec/functions/actual_spec.rb
132
+ - spec/functions/just_spec.rb
133
+ - spec/functions/maybe_spec.rb
134
+ - spec/functions/null_spec.rb
135
+ - spec/implicit_conversions_spec.rb
136
+ - spec/mimic_spec.rb
137
+ - spec/naught/null_object_builder/command_spec.rb
138
+ - spec/naught/null_object_builder_spec.rb
113
139
  - spec/naught_spec.rb
140
+ - spec/pebble_spec.rb
141
+ - spec/predicate_spec.rb
142
+ - spec/singleton_null_object_spec.rb
114
143
  - spec/spec_helper.rb
144
+ - spec/support/convertable_null.rb
115
145
  homepage: https://github.com/avdi/naught
116
146
  licenses:
117
147
  - MIT
148
+ metadata: {}
118
149
  post_install_message:
119
150
  rdoc_options: []
120
151
  require_paths:
121
152
  - lib
122
153
  required_ruby_version: !ruby/object:Gem::Requirement
123
- none: false
124
154
  requirements:
125
- - - ! '>='
155
+ - - '>='
126
156
  - !ruby/object:Gem::Version
127
157
  version: '0'
128
158
  required_rubygems_version: !ruby/object:Gem::Requirement
129
- none: false
130
159
  requirements:
131
- - - ! '>='
160
+ - - '>='
132
161
  - !ruby/object:Gem::Version
133
162
  version: '0'
134
163
  requirements: []
135
164
  rubyforge_project:
136
- rubygems_version: 1.8.24
165
+ rubygems_version: 2.0.3
137
166
  signing_key:
138
- specification_version: 3
167
+ specification_version: 4
139
168
  summary: Naught is a toolkit for building Null Objects
140
169
  test_files:
170
+ - spec/base_object_spec.rb
171
+ - spec/basic_null_object_spec.rb
172
+ - spec/blackhole_spec.rb
173
+ - spec/conversions_spec.rb
174
+ - spec/functions/actual_spec.rb
175
+ - spec/functions/just_spec.rb
176
+ - spec/functions/maybe_spec.rb
177
+ - spec/functions/null_spec.rb
178
+ - spec/implicit_conversions_spec.rb
179
+ - spec/mimic_spec.rb
180
+ - spec/naught/null_object_builder/command_spec.rb
181
+ - spec/naught/null_object_builder_spec.rb
141
182
  - spec/naught_spec.rb
183
+ - spec/pebble_spec.rb
184
+ - spec/predicate_spec.rb
185
+ - spec/singleton_null_object_spec.rb
142
186
  - spec/spec_helper.rb
143
- has_rdoc:
187
+ - spec/support/convertable_null.rb
data/.rspec DELETED
@@ -1 +0,0 @@
1
- -fs --color --order rand
data/README.org DELETED
@@ -1,340 +0,0 @@
1
- #+TITLE: Naught: A Ruby Null Object Library
2
-
3
- * A quick intro to Naught
4
-
5
- *What's all this now then?*
6
-
7
- Naught is a toolkit for building [[http://en.wikipedia.org/wiki/Null_Object_pattern][Null Objects]] in Ruby.
8
-
9
- *What's that supposed to mean?*
10
-
11
- Null Objects can make your code more [[http://confidentruby.com][confident]].
12
-
13
- Here's a method that's not very sure of itself.
14
-
15
- #+BEGIN_SRC ruby
16
- class Geordi
17
- def make_it_so(logger=nil)
18
- logger && logger.info "Reversing the flux phase capacitance!"
19
- logger && logger.info "Bounding a tachyon particle beam off of Data's cat!"
20
- logger && logger.warn "Warning, bogon levels are rising!"
21
- end
22
- end
23
- #+END_SRC
24
-
25
- Now, observe as we give it a dash of confidence with the Null Object
26
- pattern!
27
-
28
- #+BEGIN_SRC ruby
29
- class NullLogger
30
- def debug(*); end
31
- def info(*); end
32
- def warn(*); end
33
- def error(*); end
34
- def fatal(*); end
35
- end
36
-
37
- class Geordi
38
- def make_it_so(logger=NullLogger.new)
39
- logger.info "Reversing the flux phase capacitance!"
40
- logger.info "Bounding a tachyon particle beam off of Data's cat!"
41
- logger.warn "Warning, bogon levels are rising!"
42
- end
43
- end
44
- #+END_SRC
45
-
46
- By providing a =NullLogger= which implements [some of] the =Logger=
47
- interface as no-op methods, we've gotten rid of those unsightly =&&=
48
- operators.
49
-
50
- *That was simple enough. Why do I need a library for it?*
51
-
52
- You don't! The Null Object pattern is a very simple one at its core.
53
-
54
- *And yet here we are...*
55
-
56
- Yes. While you don't /need/ a Null Object library, this one offers
57
- some conveniences you probably won't find elsewhere.
58
-
59
- But there's an even more important reason I wrote this library. In
60
- the immortal last words of James T. Kirk: "It was... /fun!/"
61
-
62
- *OK, so how do I use this thing?*
63
-
64
- Well, what would you like to do?
65
-
66
- *I dunno, gimme an object that responds to any message with nil*
67
-
68
- Sure thing!
69
-
70
- #+BEGIN_SRC ruby
71
- require 'naught'
72
-
73
- NullObject = Naught.build
74
-
75
- null = NullObject.new
76
- null.foo # => nil
77
- null.bar # => nil
78
- #+END_SRC
79
-
80
- *That was... weird. What's with this "build" business?*
81
-
82
- Naught is a /toolkit/ for building null object classes. It is not a
83
- one-size-fits-all solution.
84
-
85
- What else can I make for you?
86
-
87
- *How about a "black hole" null object that supports infinite chaining
88
- of methods?*
89
-
90
- OK.
91
-
92
- #+BEGIN_SRC ruby
93
- require 'naught'
94
-
95
- BlackHole = Naught.build do |b|
96
- b.black_hole
97
- end
98
-
99
- null = BlackHole.new
100
- null.foo # => <null>
101
- null.foo.bar.baz # => <null>
102
- null << "hello" << "world" # => <null>
103
- #+END_SRC
104
-
105
- *What's that "b" thing?*
106
-
107
- That stands for "builder". Naught uses the [[http://en.wikipedia.org/wiki/Builder_pattern][Builder Pattern]] for
108
- rolling custom null object classes.
109
-
110
- *Whatever. What if I want a null object that has conversions to Integer, String, etc. using sensible conversions to "zero values"?*
111
-
112
- We can do that.
113
-
114
- #+BEGIN_SRC ruby
115
- require 'naught'
116
-
117
- NullObject = Naught.build do |b|
118
- b.define_explicit_conversions
119
- end
120
-
121
- null = NullObject.new
122
-
123
- null.to_s # => ""
124
- null.to_i # => 0
125
- null.to_f # => 0.0
126
- null.to_a # => []
127
- null.to_h # => {}
128
- null.to_c # => (0+0i)
129
- null.to_r # => (0/1)
130
- #+END_SRC
131
-
132
- *Ah, but what about implicit conversions such as #to_str? Like what if I want a null object that implicitly splats the same way as an
133
- empty array?*
134
-
135
- Gotcha covered.
136
-
137
- #+BEGIN_SRC ruby
138
- require 'naught'
139
-
140
- NullObject = Naught.build do |b|
141
- b.define_implicit_conversions
142
- end
143
-
144
- null = NullObject.new
145
-
146
- null.to_str # => ""
147
- null.to_ary # => []
148
-
149
- a, b, c = []
150
- a # => nil
151
- b # => nil
152
- c # => nil
153
- x, y, z = null
154
- x # => nil
155
- y # => nil
156
- z # => nil
157
- #+END_SRC
158
-
159
- *How about a null object that only stubs out the methods from a specific class?*
160
-
161
- That's what =mimic= is for.
162
-
163
- #+BEGIN_SRC ruby
164
- require 'naught'
165
-
166
- NullIO = Naught.build do |b|
167
- b.mimic IO
168
- end
169
-
170
- null_io = NullIO.new
171
-
172
- null_io << "foo" # => nil
173
- null_io.readline # => nil
174
- null_io.foobar # =>
175
- # ~> -:11:in `<main>': undefined method `foobar' for
176
- # <null:IO>:NullIO (NoMethodError)
177
- #+END_SRC
178
-
179
- There is also =impersonate= which takes =mimic= one step further. The
180
- generated null class will be derived from the impersonated class.
181
- This is handy when refitting legacy code that contains type checks.
182
-
183
- #+BEGIN_SRC ruby
184
- require 'naught'
185
-
186
- NullIO = Naught.build do |b|
187
- b.impersonate IO
188
- end
189
-
190
- null_io = NullIO.new
191
- IO === null_io # => true
192
-
193
- case null_io
194
- when IO
195
- puts "Yep, checks out!"
196
- null_io << "some output"
197
- else
198
- raise "Hey, I expected an IO!"
199
- end
200
- # >> Yep, checks out!
201
- #+END_SRC
202
-
203
- *Alright smartypants. What if I want to add my own methods?*
204
-
205
- Not a problem, just define them in the =.build= block.
206
-
207
- #+BEGIN_SRC ruby
208
- require 'naught'
209
-
210
- NullObject = Naught.build do |b|
211
- b.define_explicit_conversions
212
- def to_s
213
- "NOTHING TO SEE HERE MOVE ALONG"
214
- end
215
-
216
- def to_path
217
- "/dev/null"
218
- end
219
- end
220
-
221
- null = NullObject.new
222
- null.to_s # => "NOTHING TO SEE HERE MOVE ALONG"
223
- null.to_path # => "/dev/null"
224
- #+END_SRC
225
-
226
- *Got anything else up your sleeve?*
227
-
228
- Well, we can make the null class a singleton, since null objects
229
- generally have no state.
230
-
231
- #+BEGIN_SRC ruby
232
- require 'naught'
233
-
234
- NullObject = Naught.build do |b|
235
- b.singleton
236
- end
237
-
238
- null = NullObject.instance
239
-
240
- null.__id__ # => 17844080
241
- NullObject.instance.__id__ # => 17844080
242
- NullObject.new # =>
243
- # ~> -:11:in `<main>': private method `new' called for
244
- # NullObject:Class (NoMethodError)
245
- #+END_SRC
246
-
247
- Speaking of null objects with state, we can also enable tracing. This
248
- is handy for playing "where'd that null come from?!" Try doing /that/
249
- with =nil=!
250
-
251
- #+BEGIN_SRC ruby
252
- require 'naught'
253
-
254
- NullObject = Naught.build do |b|
255
- b.traceable
256
- end
257
-
258
- null = NullObject.new # line 7
259
-
260
- null.__file__ # => "example.rb"
261
- null.__line__ # => 7
262
- #+END_SRC
263
-
264
- We can even conditionally enable either singleton mode (for
265
- production) or tracing (for development). Here's an example of using
266
- the =$DEBUG= global variable (set with the =-d= option to ruby) to
267
- choose which one.
268
-
269
- #+BEGIN_SRC ruby
270
- require 'naught'
271
-
272
- NullObject = Naught.build do |b|
273
- if $DEBUG
274
- b.traceable
275
- else
276
- b.singleton
277
- end
278
- end
279
- #+END_SRC
280
-
281
- The only caveat is that when swapping between singleton and
282
- non-singleton implementations, you should be careful to always
283
- instantiate your null objects with =NullObject.get=, not =.new= or
284
- =.instance=. =.get= will work whether the class is implemented as a
285
- singleton or not.
286
-
287
- #+BEGIN_SRC ruby
288
- NullObject.get # => <null>
289
- #+END_SRC
290
-
291
- *Are you done yet?*
292
-
293
- Just one more thing. For maximum convenience, Naught-generated null
294
- classes also come with a full suite of conversion functions which can
295
- be included into your classes.
296
-
297
- #+BEGIN_SRC ruby
298
- require 'naught'
299
-
300
- NullObject = Naught.build
301
-
302
- include NullObject::Conversions
303
-
304
- # Convert nil to null objects. Everything else passes through.
305
- Maybe(42) # => 42
306
- Maybe(nil) # => <null>
307
- Maybe(NullObject.get) # => <null>
308
- Maybe{ 42 } # => 42
309
-
310
- # Insist on a non-null (or nil) value
311
- Just(42) # => 42
312
- Just(nil) rescue $! # => #<ArgumentError: Null value: nil>
313
- Just(NullObject.get) rescue $! # => #<ArgumentError: Null value: <null>>
314
-
315
- # nils and nulls become nulls. Everything else is rejected.
316
- Null() # => <null>
317
- Null(42) rescue $! # => #<ArgumentError: 42 is not null!>
318
- Null(nil) # => <null>
319
- Null(NullObject.get) # => <null>
320
-
321
- # Convert nulls back to nils. Everything else passes throuhgh. Useful
322
- # for preventing null objects from "leaking" into public API return
323
- # values.
324
- Actual(42) # => 42
325
- Actual(nil) # => nil
326
- Actual(NullObject.get) # => nil
327
- Actual { 42 } # => 42
328
- #+END_SRC
329
-
330
- * Requirements
331
-
332
- - Ruby 1.9
333
-
334
- * Contributing
335
-
336
- - Fork, branch, submit PR, blah blah blah. Don't forget tests.
337
-
338
- * Who's responsible
339
-
340
- Naught is by [[http://devblog.avdi.org/][Avdi Grimm]].