naught 0.0.1

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.
data/bin/htmldiff ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'htmldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('diff-lcs', 'htmldiff')
data/bin/ldiff ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('diff-lcs', 'ldiff')
data/bin/pry ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'pry' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('pry', 'pry')
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/bin/rspec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
data/bin/thor ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'thor' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('thor', 'thor')
data/lib/naught.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "naught/version"
2
+ require 'naught/null_class_builder'
3
+ require 'naught/null_class_builder/commands/define_explicit_conversions'
4
+
5
+ module Naught
6
+ def self.build(&customization_block)
7
+ builder = NullClassBuilder.new
8
+ builder.customize(&customization_block)
9
+ unless builder.interface_defined?
10
+ builder.respond_to_any_message
11
+ end
12
+ builder.generate_class
13
+ end
14
+ module NullObjectTag
15
+ end
16
+ end
@@ -0,0 +1,274 @@
1
+ module Naught
2
+ class NullClassBuilder
3
+ # make sure this module exists
4
+ module Commands
5
+ end
6
+
7
+ def initialize
8
+ @interface_defined = false
9
+ @base_class = BasicObject
10
+ @inspect_proc = ->{ "<null>" }
11
+ @stub_strategy = :stub_method_returning_nil
12
+ define_basic_methods
13
+ end
14
+
15
+ def interface_defined?
16
+ @interface_defined
17
+ end
18
+
19
+ def customize(&customization_block)
20
+ return unless customization_block
21
+ customization_module.module_exec(self, &customization_block)
22
+ end
23
+
24
+ def customization_module
25
+ @customization_module ||= Module.new
26
+ end
27
+
28
+ def null_equivalents
29
+ @null_equivalents ||= [nil]
30
+ end
31
+
32
+ def generate_conversions_module(null_class)
33
+ null_equivs = null_equivalents # get a local binding
34
+ @conversions_module ||= Module.new do
35
+ define_method(:Null) do |object=:nothing_passed|
36
+ case object
37
+ when NullObjectTag then object
38
+ when :nothing_passed, *null_equivs
39
+ null_class.get(caller: caller(1))
40
+ else raise ArgumentError, "#{object.inspect} is not null!"
41
+ end
42
+ end
43
+
44
+ define_method(:Maybe) do |object=nil, &block|
45
+ object = block ? block.call : object
46
+ case object
47
+ when NullObjectTag then object
48
+ when *null_equivs
49
+ null_class.get(caller: caller(1))
50
+ else
51
+ object
52
+ end
53
+ end
54
+
55
+ define_method(:Just) do |object=nil, &block|
56
+ object = block ? block.call : object
57
+ case object
58
+ when NullObjectTag, *null_equivs
59
+ raise ArgumentError, "Null value: #{object.inspect}"
60
+ else
61
+ object
62
+ end
63
+ end
64
+
65
+ define_method(:Actual) do |object=nil, &block|
66
+ object = block ? block.call : object
67
+ case object
68
+ when NullObjectTag then nil
69
+ else
70
+ object
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ def generate_class
77
+ generation_mod = Module.new
78
+ customization_mod = customization_module # get a local binding
79
+ builder = self
80
+ @operations.each do |operation|
81
+ operation.call(generation_mod)
82
+ end
83
+ null_class = Class.new(@base_class) do
84
+ const_set :GeneratedMethods, generation_mod
85
+ const_set :Customizations, customization_mod
86
+ const_set :Conversions, builder.generate_conversions_module(self)
87
+
88
+ include NullObjectTag
89
+ include generation_mod
90
+ include customization_mod
91
+ end
92
+ class_operations.each do |operation|
93
+ operation.call(null_class)
94
+ end
95
+ null_class
96
+ end
97
+
98
+ def method_missing(method_name, *args, &block)
99
+ command_name = command_name_for_method(method_name)
100
+ if Commands.const_defined?(command_name)
101
+ command_class = Commands.const_get(command_name)
102
+ command_class.new(self, *args, &block).call
103
+ else
104
+ super
105
+ end
106
+ end
107
+
108
+ def respond_to_missing?(method_name, *args)
109
+ command_name = command_name_for_method(method_name)
110
+ Commands.const_defined?(command_name) || super
111
+ end
112
+
113
+ ############################################################################
114
+ # Builder API
115
+ #
116
+ # See also the contents of lib/naught/null_class_builder/commands
117
+ ############################################################################
118
+ def define_implicit_conversions
119
+ defer do |subject|
120
+ subject.module_eval do
121
+ def to_ary; []; end
122
+ def to_str; ''; end
123
+ end
124
+ end
125
+ end
126
+
127
+ def mimic(class_to_mimic, options={})
128
+ include_super = options.fetch(:include_super) { true }
129
+ @base_class = root_class_of(class_to_mimic)
130
+ @inspect_proc = -> { "<null:#{class_to_mimic}>" }
131
+ defer do |subject|
132
+ subject.module_eval do
133
+ methods = class_to_mimic.instance_methods(include_super) -
134
+ Object.instance_methods
135
+ methods.each do |method_name|
136
+ define_method(method_name) {|*| nil}
137
+ end
138
+ end
139
+ end
140
+ @interface_defined = true
141
+ end
142
+
143
+ def black_hole
144
+ @stub_strategy = :stub_method_returning_self
145
+ end
146
+
147
+ def respond_to_any_message
148
+ defer do |subject|
149
+ subject.module_eval do
150
+ def respond_to?(*)
151
+ true
152
+ end
153
+ end
154
+ stub_method(subject, :method_missing)
155
+ end
156
+ @interface_defined = true
157
+ end
158
+
159
+ def mimic(class_to_mimic, options={})
160
+ include_super = options.fetch(:include_super) { true }
161
+ @base_class = root_class_of(class_to_mimic)
162
+ @inspect_proc = -> { "<null:#{class_to_mimic}>" }
163
+ defer do |subject|
164
+ methods = class_to_mimic.instance_methods(include_super) -
165
+ Object.instance_methods
166
+ methods.each do |method_name|
167
+ stub_method(subject, method_name)
168
+ end
169
+ end
170
+ @interface_defined = true
171
+ end
172
+
173
+ def impersonate(class_to_impersonate, options={})
174
+ mimic(class_to_impersonate, options)
175
+ @base_class = class_to_impersonate
176
+ end
177
+
178
+ def traceable
179
+ defer do |subject|
180
+ subject.module_eval do
181
+ attr_reader :__file__, :__line__
182
+
183
+ def initialize(options={})
184
+ backtrace = options.fetch(:caller) { Kernel.caller(4) }
185
+ @__file__, line, _ = backtrace[0].split(':')
186
+ @__line__ = line.to_i
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ def defer(options={}, &deferred_operation)
193
+ if options[:class]
194
+ class_operations << deferred_operation
195
+ else
196
+ operations << deferred_operation
197
+ end
198
+ end
199
+
200
+ def singleton
201
+ defer(class: true) do |subject|
202
+ require 'singleton'
203
+ subject.module_eval do
204
+ include Singleton
205
+ def self.get(*)
206
+ instance
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ def define_basic_methods
213
+ defer do |subject|
214
+ # make local variable to be accessible to Class.new block
215
+ inspect_proc = @inspect_proc
216
+ subject.module_eval do
217
+ define_method(:inspect, &inspect_proc)
218
+ def initialize(*)
219
+ end
220
+ end
221
+ end
222
+ defer(class: true) do |subject|
223
+ subject.module_eval do
224
+ class << self
225
+ alias get new
226
+ end
227
+ klass = self
228
+ define_method(:class) { klass }
229
+ end
230
+ end
231
+ end
232
+
233
+ private
234
+
235
+ def class_operations
236
+ @class_operations ||= []
237
+ end
238
+
239
+ def operations
240
+ @operations ||= []
241
+ end
242
+
243
+ def stub_method(subject, name)
244
+ send(@stub_strategy, subject, name)
245
+ end
246
+
247
+ def stub_method_returning_nil(subject, name)
248
+ subject.module_eval do
249
+ define_method(name) {|*| nil }
250
+ end
251
+ end
252
+
253
+ def stub_method_returning_self(subject, name)
254
+ subject.module_eval do
255
+ define_method(name) {|*| self }
256
+ end
257
+ end
258
+
259
+ def command_name_for_method(method_name)
260
+ command_name = method_name.to_s.
261
+ gsub(/_(\w)/){ $1.upcase }.
262
+ gsub(/\A(\w)/){ $1.upcase }
263
+ end
264
+
265
+ def root_class_of(klass)
266
+ if klass.ancestors.include?(Object)
267
+ Object
268
+ else
269
+ BasicObject
270
+ end
271
+ end
272
+
273
+ end
274
+ end
@@ -0,0 +1,30 @@
1
+
2
+ module Naught
3
+ class NullClassBuilder
4
+ module Commands
5
+ class DefineExplicitConversions
6
+ def initialize(builder)
7
+ @builder = builder
8
+ end
9
+
10
+ def call
11
+ defer do |subject|
12
+ subject.module_eval do
13
+ def to_s; ""; end
14
+ def to_i; 0; end
15
+ def to_f; 0.0; end
16
+ def to_c; 0.to_c; end
17
+ def to_r; 0.to_r; end
18
+ def to_a; []; end
19
+ def to_h; {}; end
20
+ end
21
+ end
22
+ end
23
+
24
+ def defer(&block)
25
+ @builder.defer(&block)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Naught
2
+ VERSION = "0.0.1"
3
+ end
data/naught.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'naught/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "naught"
8
+ spec.version = Naught::VERSION
9
+ spec.authors = ["Avdi Grimm"]
10
+ spec.email = ["avdi@avdi.org"]
11
+ spec.description = %q{Naught is a toolkit for building Null Objects}
12
+ spec.summary = %q{Naught is a toolkit for building Null Objects}
13
+ spec.homepage = "https://github.com/avdi/naught"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "guard"
25
+ spec.add_development_dependency "guard-rspec"
26
+ end