naught 0.0.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.rubocop.yml +74 -0
  4. data/.travis.yml +20 -2
  5. data/Changelog.md +8 -2
  6. data/Gemfile +24 -2
  7. data/README.markdown +30 -7
  8. data/Rakefile +11 -2
  9. data/lib/naught.rb +1 -1
  10. data/lib/naught/basic_object.rb +17 -0
  11. data/lib/naught/conversions.rb +55 -0
  12. data/lib/naught/null_class_builder.rb +33 -21
  13. data/lib/naught/null_class_builder/command.rb +3 -3
  14. data/lib/naught/null_class_builder/commands/define_explicit_conversions.rb +3 -7
  15. data/lib/naught/null_class_builder/commands/define_implicit_conversions.rb +7 -2
  16. data/lib/naught/null_class_builder/commands/impersonate.rb +2 -3
  17. data/lib/naught/null_class_builder/commands/mimic.rb +4 -7
  18. data/lib/naught/null_class_builder/commands/pebble.rb +3 -5
  19. data/lib/naught/null_class_builder/commands/predicates_return.rb +1 -2
  20. data/lib/naught/null_class_builder/commands/singleton.rb +1 -1
  21. data/lib/naught/null_class_builder/commands/traceable.rb +3 -2
  22. data/lib/naught/version.rb +1 -1
  23. data/naught.gemspec +11 -16
  24. data/spec/base_object_spec.rb +2 -2
  25. data/spec/basic_null_object_spec.rb +3 -3
  26. data/spec/blackhole_spec.rb +4 -4
  27. data/spec/explicit_conversions_spec.rb +23 -0
  28. data/spec/functions/actual_spec.rb +4 -4
  29. data/spec/functions/just_spec.rb +7 -7
  30. data/spec/functions/maybe_spec.rb +7 -7
  31. data/spec/functions/null_spec.rb +6 -6
  32. data/spec/implicit_conversions_spec.rb +5 -5
  33. data/spec/mimic_spec.rb +30 -35
  34. data/spec/naught/null_object_builder/command_spec.rb +1 -1
  35. data/spec/naught/null_object_builder_spec.rb +5 -5
  36. data/spec/naught_spec.rb +29 -23
  37. data/spec/pebble_spec.rb +13 -11
  38. data/spec/predicate_spec.rb +18 -14
  39. data/spec/singleton_null_object_spec.rb +4 -4
  40. data/spec/spec_helper.rb +4 -4
  41. data/spec/support/convertable_null.rb +2 -2
  42. data/spec/support/jruby.rb +3 -0
  43. data/spec/support/rubinius.rb +3 -0
  44. data/spec/support/ruby_18.rb +3 -0
  45. metadata +21 -82
  46. data/lib/naught/null_class_builder/conversions_module.rb +0 -57
  47. data/spec/conversions_spec.rb +0 -20
@@ -8,11 +8,11 @@ module Naught
8
8
  end
9
9
 
10
10
  def call
11
- raise NotImplementedError,
12
- "Method #call should be overriden in child classes"
11
+ fail NotImplementedError,
12
+ 'Method #call should be overriden in child classes'
13
13
  end
14
14
 
15
- def defer(options={}, &block)
15
+ def defer(options = {}, &block)
16
16
  @builder.defer(options, &block)
17
17
  end
18
18
  end
@@ -1,3 +1,4 @@
1
+ require 'forwardable'
1
2
  require 'naught/null_class_builder/command'
2
3
 
3
4
  module Naught::NullClassBuilder::Commands
@@ -5,13 +6,8 @@ module Naught::NullClassBuilder::Commands
5
6
  def call
6
7
  defer do |subject|
7
8
  subject.module_eval do
8
- def to_s; ""; end
9
- def to_i; 0; end
10
- def to_f; 0.0; end
11
- def to_c; 0.to_c; end
12
- def to_r; 0.to_r; end
13
- def to_a; []; end
14
- def to_h; {}; end
9
+ extend Forwardable
10
+ def_delegators :nil, :to_a, :to_c, :to_f, :to_h, :to_i, :to_r, :to_s
15
11
  end
16
12
  end
17
13
  end
@@ -5,8 +5,13 @@ module Naught::NullClassBuilder::Commands
5
5
  def call
6
6
  defer do |subject|
7
7
  subject.module_eval do
8
- def to_ary; []; end
9
- def to_str; ''; end
8
+ def to_ary
9
+ []
10
+ end
11
+
12
+ def to_str
13
+ ''
14
+ end
10
15
  end
11
16
  end
12
17
  end
@@ -1,9 +1,8 @@
1
1
  module Naught::NullClassBuilder::Commands
2
2
  class Impersonate < Naught::NullClassBuilder::Commands::Mimic
3
- def initialize(builder, class_to_impersonate, options={})
3
+ def initialize(builder, class_to_impersonate, options = {})
4
4
  super
5
-
6
- builder.base_class = class_to_impersonate
5
+ builder.base_class = class_to_impersonate
7
6
  end
8
7
  end
9
8
  end
@@ -1,17 +1,18 @@
1
+ require 'naught/basic_object'
1
2
  require 'naught/null_class_builder/command'
2
3
 
3
4
  module Naught::NullClassBuilder::Commands
4
5
  class Mimic < Naught::NullClassBuilder::Command
5
6
  attr_reader :class_to_mimic, :include_super
6
7
 
7
- def initialize(builder, class_to_mimic, options={})
8
+ def initialize(builder, class_to_mimic, options = {})
8
9
  super(builder)
9
10
 
10
11
  @class_to_mimic = class_to_mimic
11
12
  @include_super = options.fetch(:include_super) { true }
12
13
 
13
14
  builder.base_class = root_class_of(class_to_mimic)
14
- builder.inspect_proc = -> { "<null:#{class_to_mimic}>" }
15
+ builder.inspect_proc = lambda { "<null:#{class_to_mimic}>" }
15
16
  builder.interface_defined = true
16
17
  end
17
18
 
@@ -26,11 +27,7 @@ module Naught::NullClassBuilder::Commands
26
27
  private
27
28
 
28
29
  def root_class_of(klass)
29
- if klass.ancestors.include?(Object)
30
- Object
31
- else
32
- BasicObject
33
- end
30
+ klass.ancestors.include?(Object) ? Object : Naught::BasicObject
34
31
  end
35
32
 
36
33
  def methods_to_stub
@@ -4,8 +4,7 @@ module Naught
4
4
  class NullClassBuilder
5
5
  module Commands
6
6
  class Pebble < ::Naught::NullClassBuilder::Command
7
-
8
- def initialize(builder, output=$stdout)
7
+ def initialize(builder, output = $stdout)
9
8
  @builder = builder
10
9
  @output = output
11
10
  end
@@ -15,18 +14,17 @@ module Naught
15
14
  subject.module_exec(@output) do |output|
16
15
 
17
16
  define_method(:method_missing) do |method_name, *args, &block|
18
- pretty_args = args.map(&:inspect).join(", ").gsub("\"", "'")
17
+ pretty_args = args.collect(&:inspect).join(', ').gsub("\"", "'")
19
18
  output.puts "#{method_name}(#{pretty_args}) from #{parse_caller}"
20
19
  self
21
20
  end
22
21
 
23
- private
24
-
25
22
  def parse_caller
26
23
  caller = Kernel.caller(2).first
27
24
  method_name = caller.match(/\`([\w\s]+(\(\d+\s\w+\))?[\w\s]*)/)
28
25
  method_name ? method_name[1] : caller
29
26
  end
27
+ private :parse_caller
30
28
  end
31
29
  end
32
30
  end
@@ -20,8 +20,7 @@ module Naught::NullClassBuilder::Commands
20
20
  subject.module_exec(@predicate_return_value) do |return_value|
21
21
  if subject.method_defined?(:method_missing)
22
22
  original_method_missing = instance_method(:method_missing)
23
- define_method(:method_missing) do
24
- |method_name, *args, &block|
23
+ define_method(:method_missing) do |method_name, *args, &block|
25
24
  if method_name.to_s.end_with?('?')
26
25
  return_value
27
26
  else
@@ -3,7 +3,7 @@ require 'naught/null_class_builder/command'
3
3
  module Naught::NullClassBuilder::Commands
4
4
  class Singleton < Naught::NullClassBuilder::Command
5
5
  def call
6
- defer(class: true) do |subject|
6
+ defer(:class => true) do |subject|
7
7
  require 'singleton'
8
8
  subject.module_eval do
9
9
  include ::Singleton
@@ -7,8 +7,9 @@ module Naught::NullClassBuilder::Commands
7
7
  subject.module_eval do
8
8
  attr_reader :__file__, :__line__
9
9
 
10
- def initialize(options={})
11
- backtrace = options.fetch(:caller) { Kernel.caller(4) }
10
+ def initialize(options = {})
11
+ range = (RUBY_VERSION.to_f == 1.9 && RUBY_PLATFORM != 'java') ? 4 : 3
12
+ backtrace = options.fetch(:caller) { Kernel.caller(range) }
12
13
  @__file__, line, _ = backtrace[0].split(':')
13
14
  @__line__ = line.to_i
14
15
  end
@@ -1,3 +1,3 @@
1
1
  module Naught
2
- VERSION = "0.0.3"
2
+ VERSION = '1.0.0'
3
3
  end
@@ -4,24 +4,19 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'naught/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "naught"
7
+ spec.name = 'naught'
8
8
  spec.version = Naught::VERSION
9
- spec.authors = ["Avdi Grimm"]
10
- spec.email = ["avdi@avdi.org"]
9
+ spec.authors = ['Avdi Grimm']
10
+ spec.email = ['avdi@avdi.org']
11
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"
12
+ spec.summary = spec.description
13
+ spec.homepage = 'https://github.com/avdi/naught'
14
+ spec.license = 'MIT'
15
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"]
16
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- spec.add_development_dependency "rspec", "~> 2.14"
24
- spec.add_development_dependency "guard"
25
- spec.add_development_dependency "guard-rspec"
26
- spec.add_development_dependency "guard-bundler"
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
27
22
  end
@@ -11,7 +11,7 @@ describe 'null object with a custom base class' do
11
11
  end
12
12
 
13
13
  it 'respond to base class methods' do
14
- expect(null.methods).to be_a_kind_of(Array)
14
+ expect(null.methods).to be_an Array
15
15
  end
16
16
 
17
17
  it 'respond to unknown methods' do
@@ -23,7 +23,7 @@ describe 'null object with a custom base class' do
23
23
  Naught.build do |b|
24
24
  default_base_class = b.base_class
25
25
  end
26
- expect(default_base_class).to eq(BasicObject)
26
+ expect(default_base_class).to eq(Naught::BasicObject)
27
27
  end
28
28
 
29
29
  describe 'singleton null object' do
@@ -11,7 +11,7 @@ describe 'basic null object' do
11
11
  end
12
12
 
13
13
  it 'accepts any arguments for any messages' do
14
- null.foobaz(1,2,3)
14
+ null.foobaz(1, 2, 3)
15
15
  end
16
16
 
17
17
  it 'reports that it responds to any message' do
@@ -21,7 +21,7 @@ describe 'basic null object' do
21
21
  end
22
22
 
23
23
  it 'can be inspected' do
24
- expect(null.inspect).to eq("<null>")
24
+ expect(null.inspect).to eq('<null>')
25
25
  end
26
26
 
27
27
  it 'knows its own class' do
@@ -32,4 +32,4 @@ describe 'basic null object' do
32
32
  expect(null_class.get.class).to be(null_class)
33
33
  end
34
34
 
35
- end
35
+ end
@@ -2,15 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  describe 'black hole null object' do
4
4
  subject(:null) { null_class.new }
5
- let(:null_class) {
5
+ let(:null_class) do
6
6
  Naught.build do |b|
7
7
  b.black_hole
8
8
  end
9
- }
9
+ end
10
10
 
11
11
  it 'returns self from arbitray method calls' do
12
12
  expect(null.info).to be(null)
13
13
  expect(null.foobaz).to be(null)
14
- expect(null << "bar").to be(null)
14
+ expect(null << 'bar').to be(null)
15
15
  end
16
- end
16
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe 'explicitly convertable null object' do
4
+ let(:null_class) do
5
+ Naught.build do |b|
6
+ b.define_explicit_conversions
7
+ end
8
+ end
9
+ subject(:null) { null_class.new }
10
+
11
+ it 'defines common explicit conversions to return zero values' do
12
+ expect(null.to_s).to eq('')
13
+ expect(null.to_a).to eq([])
14
+ expect(null.to_i).to eq(0)
15
+ expect(null.to_f).to eq(0.0)
16
+ if RUBY_VERSION >= '2.0'
17
+ expect(null.to_h).to eq({})
18
+ elsif RUBY_VERSION >= '1.9'
19
+ expect(null.to_c).to eq(Complex(0))
20
+ expect(null.to_r).to eq(Rational(0))
21
+ end
22
+ end
23
+ end
@@ -10,13 +10,13 @@ describe 'Actual()' do
10
10
 
11
11
  specify 'given anything else, returns the input unchanged' do
12
12
  expect(Actual(false)).to be(false)
13
- str = "hello"
13
+ str = 'hello'
14
14
  expect(Actual(str)).to be(str)
15
15
  expect(Actual(nil)).to be_nil
16
16
  end
17
17
 
18
18
  it 'also works with blocks' do
19
- expect(Actual{ConvertableNull.new}).to be_nil
20
- expect(Actual{"foo"}).to eq("foo")
19
+ expect(Actual { ConvertableNull.new }).to be_nil
20
+ expect(Actual { 'foo' }).to eq('foo')
21
21
  end
22
- end
22
+ end
@@ -5,18 +5,18 @@ describe 'Just()' do
5
5
 
6
6
  specify 'passes non-nullish values through' do
7
7
  expect(Just(false)).to be(false)
8
- str = "hello"
8
+ str = 'hello'
9
9
  expect(Just(str)).to be(str)
10
10
  end
11
11
 
12
12
  specify 'rejects nullish values' do
13
- expect{Just(nil)}.to raise_error(ArgumentError)
14
- expect{Just("")}.to raise_error(ArgumentError)
15
- expect{Just(ConvertableNull.get)}.to raise_error(ArgumentError)
13
+ expect { Just(nil) }.to raise_error(ArgumentError)
14
+ expect { Just('') }.to raise_error(ArgumentError)
15
+ expect { Just(ConvertableNull.get) }.to raise_error(ArgumentError)
16
16
  end
17
17
 
18
18
  it 'also works with blocks' do
19
- expect{Just{nil}.class}.to raise_error(ArgumentError)
20
- expect(Just{"foo"}).to eq("foo")
19
+ expect { Just { nil }.class }.to raise_error(ArgumentError)
20
+ expect(Just { 'foo' }).to eq('foo')
21
21
  end
22
- end
22
+ end
@@ -13,23 +13,23 @@ describe 'Maybe()' do
13
13
  end
14
14
 
15
15
  specify 'given anything in null_equivalents, return a null object' do
16
- expect(Maybe("").class).to be(ConvertableNull)
16
+ expect(Maybe('').class).to be(ConvertableNull)
17
17
  end
18
18
 
19
19
  specify 'given anything else, returns the input unchanged' do
20
20
  expect(Maybe(false)).to be(false)
21
- str = "hello"
21
+ str = 'hello'
22
22
  expect(Maybe(str)).to be(str)
23
23
  end
24
24
 
25
25
  it 'generates null objects with useful trace info' do
26
- null = Maybe(); line = __LINE__
27
- expect(null.__line__).to eq(line)
26
+ null, line = Maybe(), __LINE__
28
27
  expect(null.__file__).to eq(__FILE__)
28
+ expect(null.__line__).to eq(line)
29
29
  end
30
30
 
31
31
  it 'also works with blocks' do
32
- expect(Maybe{nil}.class).to eq(ConvertableNull)
33
- expect(Maybe{"foo"}).to eq("foo")
32
+ expect(Maybe { nil }.class).to eq(ConvertableNull)
33
+ expect(Maybe { 'foo' }).to eq('foo')
34
34
  end
35
- end
35
+ end
@@ -17,18 +17,18 @@ describe 'Null()' do
17
17
  end
18
18
 
19
19
  specify 'given anything in null_equivalents, return a null object' do
20
- expect(Null("").class).to be(ConvertableNull)
20
+ expect(Null('').class).to be(ConvertableNull)
21
21
  end
22
22
 
23
23
  specify 'given anything else, raises an ArgumentError' do
24
- expect{Null(false)}.to raise_error(ArgumentError)
25
- expect{Null("hello")}.to raise_error(ArgumentError)
24
+ expect { Null(false) }.to raise_error(ArgumentError)
25
+ expect { Null('hello') }.to raise_error(ArgumentError)
26
26
  end
27
27
 
28
28
  it 'generates null objects with useful trace info' do
29
- null = Null(); line = __LINE__
30
- expect(null.__line__).to eq(line)
29
+ null, line = Null(), __LINE__
31
30
  expect(null.__file__).to eq(__FILE__)
31
+ expect(null.__line__).to eq(line)
32
32
  end
33
33
 
34
- end
34
+ end
@@ -2,24 +2,24 @@ require 'spec_helper'
2
2
 
3
3
  describe 'implicitly convertable null object' do
4
4
  subject(:null) { null_class.new }
5
- let(:null_class) {
5
+ let(:null_class) do
6
6
  Naught.build do |b|
7
7
  b.define_implicit_conversions
8
8
  end
9
- }
9
+ end
10
10
  it 'implicitly splats the same way an empty array does' do
11
11
  a, b = null
12
12
  expect(a).to be_nil
13
13
  expect(b).to be_nil
14
14
  end
15
15
  it 'is implicitly convertable to String' do
16
- expect(eval(null)).to be_nil
16
+ expect(instance_eval(null)).to be_nil
17
17
  end
18
18
  it 'implicitly converts to an empty array' do
19
19
  expect(null.to_ary).to eq([])
20
20
  end
21
21
  it 'implicitly converts to an empty string' do
22
- expect(null.to_str).to eq("")
22
+ expect(null.to_str).to eq('')
23
23
  end
24
24
 
25
- end
25
+ end
@@ -3,27 +3,39 @@ require 'logger'
3
3
 
4
4
  describe 'null object mimicking a class' do
5
5
  class User
6
- def login; "bob"; end
6
+ def login
7
+ 'bob'
8
+ end
7
9
  end
8
10
 
9
11
  module Authorizable
10
- def authorized_for?(object); true; end
12
+ def authorized_for?(object)
13
+ true
14
+ end
11
15
  end
12
16
 
13
17
  class LibraryPatron < User
14
18
  include Authorizable
15
19
 
16
- def member?; true; end
17
- def name; "Bob"; end
18
- def notify_of_overdue_books(titles); puts 'Notifying...'; end
20
+ def member?
21
+ true
22
+ end
23
+
24
+ def name
25
+ 'Bob'
26
+ end
27
+
28
+ def notify_of_overdue_books(titles)
29
+ puts 'Notifying...'
30
+ end
19
31
  end
20
32
 
21
33
  subject(:null) { mimic_class.new }
22
- let(:mimic_class) {
34
+ let(:mimic_class) do
23
35
  Naught.build do |b|
24
36
  b.mimic LibraryPatron
25
37
  end
26
- }
38
+ end
27
39
  it 'responds to all methods defined on the target class' do
28
40
  expect(null.member?).to be_nil
29
41
  expect(null.name).to be_nil
@@ -31,7 +43,7 @@ describe 'null object mimicking a class' do
31
43
  end
32
44
 
33
45
  it 'does not respond to methods not defined on the target class' do
34
- expect{null.foobar}.to raise_error(NoMethodError)
46
+ expect { null.foobar }.to raise_error(NoMethodError)
35
47
  end
36
48
 
37
49
  it 'reports which messages it does and does not respond to' do
@@ -41,7 +53,7 @@ describe 'null object mimicking a class' do
41
53
  expect(null).not_to respond_to(:foobar)
42
54
  end
43
55
  it 'has an informative inspect string' do
44
- expect(null.inspect).to eq("<null:LibraryPatron>")
56
+ expect(null.inspect).to eq('<null:LibraryPatron>')
45
57
  end
46
58
 
47
59
  it 'excludes Object methods from being mimicked' do
@@ -55,11 +67,11 @@ describe 'null object mimicking a class' do
55
67
  end
56
68
 
57
69
  describe 'with include_super: false' do
58
- let(:mimic_class) {
70
+ let(:mimic_class) do
59
71
  Naught.build do |b|
60
- b.mimic LibraryPatron, include_super: false
72
+ b.mimic LibraryPatron, :include_super => false
61
73
  end
62
- }
74
+ end
63
75
 
64
76
  it 'excludes inherited methods' do
65
77
  expect(null).to_not respond_to(:authorized_for?)
@@ -70,53 +82,36 @@ end
70
82
 
71
83
  describe 'using mimic with black_hole' do
72
84
  subject(:null) { mimic_class.new }
73
- let(:mimic_class) {
85
+ let(:mimic_class) do
74
86
  Naught.build do |b|
75
87
  b.mimic Logger
76
88
  b.black_hole
77
89
  end
78
- }
90
+ end
79
91
 
80
92
  def self.it_behaves_like_a_black_hole_mimic
81
93
  it 'returns self from mimicked methods' do
82
94
  expect(null.info).to equal(null)
83
95
  expect(null.error).to equal(null)
84
- expect(null << "test").to equal(null)
96
+ expect(null << 'test').to equal(null)
85
97
  end
86
98
 
87
99
  it 'does not respond to methods not defined on the target class' do
88
- expect{null.foobar}.to raise_error(NoMethodError)
100
+ expect { null.foobar }.to raise_error(NoMethodError)
89
101
  end
90
102
  end
91
103
 
92
104
  it_behaves_like_a_black_hole_mimic
93
105
 
94
106
  describe '(reverse order)' do
95
- let(:mimic_class) {
107
+ let(:mimic_class) do
96
108
  Naught.build do |b|
97
109
  b.black_hole
98
110
  b.mimic Logger
99
111
  end
100
- }
112
+ end
101
113
 
102
114
  it_behaves_like_a_black_hole_mimic
103
115
  end
104
116
 
105
117
  end
106
-
107
- describe 'mimicking a non-Object-derived class' do
108
- class MinimalClass < BasicObject
109
- end
110
-
111
- subject(:null) { mimic_class.new }
112
- let(:mimic_class) {
113
- Naught.build do |b|
114
- b.mimic MinimalClass
115
- end
116
- }
117
-
118
- it 'generates a BasicObject-derived null class' do
119
- expect(BasicObject).to be === null
120
- expect(Object).not_to be === null
121
- end
122
- end