naught 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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]].