adamantium 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NzMwMWQ3ODI1Y2FlYTlhNTFjZjhlYTM3NWMyOTgwZjk4NmI4ODFjYg==
5
- data.tar.gz: !binary |-
6
- M2RmNzViMTg3YjcxNDdmMDg4ZTBmZTAzMWY5MDYzMDg0Y2U4MGZjZg==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- NjU3MDcxN2UzNzU1ZWZlYzEyY2VkMzgzNWJiNTFhNDc0MmMzNWZhNzJkOGYy
10
- YTRkNjhkMTRiMmIyMzAwZjk0Yjk2NDJlMmZjODY3NTVhNTNlZDcwZDgwMjMx
11
- ODRjYjZmOGE4OTZlODNmNTIwMDJiYzE0N2ViNmE2NmQ5YjFiNTM=
12
- data.tar.gz: !binary |-
13
- ODY0NDUyODM1YTg3OTMwMWJlMTU4YzFhNzUzZmY1NGE1NWE0ZTQzMmRiMDEz
14
- ZWExY2RhY2Y4YWQ3MTI1MjBlODRhODlhNWE2Y2ZlYjMxMmI5YjgzYWNhM2Uy
15
- YTY0NWMwYjNmYzc1ZjcxMWU1OThlMWQyNjgwYWE0NzM2YWZiZjk=
2
+ SHA1:
3
+ metadata.gz: 4675912f9a7cb3eb823638436c1be23e6753d24b
4
+ data.tar.gz: cbf0680ce697e2da134bc86d83582a1928952d8e
5
+ SHA512:
6
+ metadata.gz: 81ab12f754e252929d3074a9a85f53af07a3a93d8db946beac48124f6f03c7528741d1716e221fb07eac9daf95031e9e2847aa72509135fd017a71a1dcfbbb53
7
+ data.tar.gz: 5c7246f7aaab383bd952af49971a6046dc953f96a2553e8c2e7539191bb53408a9fb0ebb71e215714d5250aa8fef426d7330dded7c090b13ba38883e45b84fa0
data/.gitignore CHANGED
@@ -1,4 +1,37 @@
1
- /Gemfile.lock
2
- /coverage
3
- /tmp
4
- /.rbx
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.sw[op]
15
+
16
+ ## Rubinius
17
+ *.rbc
18
+ .rbx
19
+
20
+ ## PROJECT::GENERAL
21
+ *.gem
22
+ coverage
23
+ profiling
24
+ turbulence
25
+ rdoc
26
+ pkg
27
+ tmp
28
+ doc
29
+ log
30
+ .yardoc
31
+ measurements
32
+
33
+ ## BUNDLER
34
+ .bundle
35
+ Gemfile.lock
36
+
37
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,6 @@
1
+ AllCops:
2
+ Includes:
3
+ - 'Gemfile'
4
+ Excludes:
5
+ - 'Gemfile.devtools'
6
+ - 'vendor/**'
@@ -1,23 +1,26 @@
1
1
  language: ruby
2
2
  before_install: gem install bundler
3
3
  bundler_args: --without yard guard benchmarks
4
- script: "bundle exec rake ci"
4
+ script: "bundle exec rake ci:metrics"
5
5
  rvm:
6
6
  - 1.9.3
7
7
  - 2.0.0
8
+ - 2.1.0
8
9
  - ruby-head
9
- - rbx-19mode
10
+ - rbx
10
11
  matrix:
11
12
  include:
12
13
  - rvm: jruby-19mode
13
- env: JRUBY_OPTS="$JRUBY_OPTS --debug"
14
+ env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov
15
+ - rvm: jruby-20mode
16
+ env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov
17
+ - rvm: jruby-21mode
18
+ env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov
14
19
  - rvm: jruby-head
15
- env: JRUBY_OPTS="$JRUBY_OPTS --debug"
20
+ env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov
16
21
  allow_failures:
17
- - rvm: 1.9.3 # mutant fails
18
- - rvm: 2.0.0 # mutant fails
19
- - rvm: ruby-head # travis broken
20
- - rvm: rbx-19mode # mutant fails
22
+ - rvm: 2.1.0 # buggy runtime
23
+ fast_finish: true
21
24
  notifications:
22
25
  irc:
23
26
  channels:
@@ -4,21 +4,24 @@ group :development do
4
4
  gem 'rake', '~> 10.1.0'
5
5
  gem 'rspec', '~> 2.14.1'
6
6
  gem 'yard', '~> 0.8.7'
7
+
8
+ platform :rbx do
9
+ gem 'rubysl-singleton', '~> 2.0.0'
10
+ end
7
11
  end
8
12
 
9
13
  group :yard do
10
- gem 'kramdown', '~> 1.1.0'
14
+ gem 'kramdown', '~> 1.3.0'
11
15
  end
12
16
 
13
17
  group :guard do
14
- gem 'guard', '~> 1.8.1'
15
- gem 'guard-bundler', '~> 1.0.0'
16
- gem 'guard-rspec', '~> 3.0.2'
17
- gem 'guard-rubocop', '~> 0.2.0'
18
- # gem 'guard-mutant', '~> 0.0.1'
18
+ gem 'guard', '~> 2.3.0'
19
+ gem 'guard-bundler', '~> 2.0.0'
20
+ gem 'guard-rspec', '~> 4.2.0'
21
+ gem 'guard-rubocop', '~> 1.0.0'
19
22
 
20
23
  # file system change event handling
21
- gem 'listen', '~> 1.3.0'
24
+ gem 'listen', '~> 2.4.0'
22
25
  gem 'rb-fchange', '~> 0.0.6', require: false
23
26
  gem 'rb-fsevent', '~> 0.9.3', require: false
24
27
  gem 'rb-inotify', '~> 0.9.0', require: false
@@ -30,18 +33,29 @@ group :guard do
30
33
  end
31
34
 
32
35
  group :metrics do
33
- gem 'coveralls', '~> 0.6.7'
36
+ gem 'coveralls', '~> 0.7.0'
34
37
  gem 'flay', '~> 2.4.0'
35
- gem 'flog', '~> 4.1.1'
38
+ gem 'flog', '~> 4.2.0'
36
39
  gem 'reek', '~> 1.3.2'
37
- gem 'rubocop', '~> 0.11.0'
38
- gem 'simplecov', '~> 0.7.1'
39
- gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
40
+ gem 'rubocop', '~> 0.16.0'
41
+ gem 'simplecov', '~> 0.8.2'
42
+ gem 'yardstick', '~> 0.9.9'
43
+
44
+ platforms :mri do
45
+ gem 'mutant', '~> 0.3.4'
46
+ end
40
47
 
41
48
  platforms :ruby_19, :ruby_20 do
42
- # gem 'mutant', git: 'https://github.com/mbj/mutant.git'
43
49
  gem 'yard-spellcheck', '~> 0.1.5'
44
50
  end
51
+
52
+ platform :rbx do
53
+ gem 'json', '~> 1.8.1'
54
+ gem 'racc', '~> 1.4'
55
+ gem 'rubysl-logger', '~> 2.0.0'
56
+ gem 'rubysl-open-uri', '~> 2.0.0'
57
+ gem 'rubysl-prettyprint', '~> 2.0.2'
58
+ end
45
59
  end
46
60
 
47
61
  group :benchmarks do
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  adamantium
2
2
  ==========
3
3
 
4
- Create immutable objects
4
+ Create immutable objects with ease.
5
5
 
6
6
  [![Gem Version](https://badge.fury.io/rb/adamantium.png)][gem]
7
7
  [![Build Status](https://secure.travis-ci.org/dkubb/adamantium.png?branch=master)][travis]
@@ -16,7 +16,7 @@ Create immutable objects
16
16
  [coveralls]: https://coveralls.io/r/dkubb/adamantium
17
17
 
18
18
  This is a small standalone gem featuring a module ripped out from [axiom](https://github.com/dkubb/axiom).
19
- It allows to make objects immutable in an unobtrusive way.
19
+ It allows you to make objects immutable in a simple, unobtrusive way.
20
20
 
21
21
  Examples
22
22
  --------
@@ -70,7 +70,7 @@ class Example
70
70
  end
71
71
  memoize :buffer, freezer: :noop
72
72
 
73
- # Memoized method with nondeeply frozen value
73
+ # Memoized method with shallow frozen value
74
74
  # Example:
75
75
  #
76
76
  # object = Example.new
@@ -86,12 +86,12 @@ class Example
86
86
  end
87
87
 
88
88
  class FlatExample
89
- # Inclusion of Adamantium::Flat defaults do non deep frozen behavior
90
- # for memoizer and constructor
89
+ # Inclusion of Adamantium::Flat defaults to shallow frozen
90
+ # behavior for memoizer and constructor
91
91
 
92
92
  include Adamantium::Flat
93
93
 
94
- # Instace is frozen but attribute is not
94
+ # Instance is frozen but attribute is not
95
95
  # object = FlatExample.new
96
96
  # object.frozen? # => true
97
97
  # object.attribute.frozen? # => false
@@ -100,7 +100,7 @@ class FlatExample
100
100
  end
101
101
  attr_reader :attribute
102
102
 
103
- # Memoized method with flat frozen value (default)
103
+ # Memoized method with flat frozen value (default with Adamantium::Flat)
104
104
  # Example:
105
105
  #
106
106
  # object = Example.new
@@ -10,15 +10,15 @@ Gem::Specification.new do |gem|
10
10
  gem.description = 'Immutable extensions to objects'
11
11
  gem.summary = gem.description
12
12
  gem.homepage = 'https://github.com/dkubb/adamantium'
13
- gem.licenses = 'MIT'
13
+ gem.license = 'MIT'
14
14
 
15
15
  gem.require_paths = %w[lib]
16
16
  gem.files = `git ls-files`.split("\n")
17
17
  gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n")
18
18
  gem.extra_rdoc_files = %w[LICENSE README.md CONTRIBUTING.md TODO]
19
19
 
20
- gem.add_runtime_dependency('ice_nine', '~> 0.9')
21
- gem.add_runtime_dependency('thread_safe', '~> 0.1.2')
20
+ gem.add_runtime_dependency('ice_nine', '~> 0.11.0')
21
+ gem.add_runtime_dependency('memoizable', '~> 0.4.0')
22
22
 
23
- gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5')
23
+ gem.add_development_dependency('bundler', '~> 1.5', '>= 1.5.2')
24
24
  end
@@ -1,3 +1,3 @@
1
1
  ---
2
- threshold: 7
3
- total_score: 54
2
+ threshold: 4
3
+ total_score: 28
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 17.5
2
+ threshold: 15.0
@@ -10,7 +10,8 @@ ClassVariable:
10
10
  exclude: []
11
11
  ControlParameter:
12
12
  enabled: true
13
- exclude: []
13
+ exclude:
14
+ - Adamantium#transform_unless
14
15
  DataClump:
15
16
  enabled: true
16
17
  exclude: []
@@ -1,10 +1,4 @@
1
- AllCops:
2
- Includes:
3
- - '**/*.rake'
4
- - 'Gemfile'
5
- - 'Gemfile.devtools'
6
- Excludes:
7
- - '**/vendor/**'
1
+ inherit_from: ../.rubocop.yml
8
2
 
9
3
  # Avoid parameter lists longer than five parameters.
10
4
  ParameterLists:
@@ -29,7 +23,7 @@ CollectionMethods:
29
23
  # sections of code and visually separate them. When the keyword is at the same
30
24
  # level I think it sort of blends in with the def keywords and makes it harder
31
25
  # to scan the code and see where the sections are.
32
- AccessControl:
26
+ AccessModifierIndentation:
33
27
  Enabled: false
34
28
 
35
29
  # Limit line length
@@ -55,3 +49,7 @@ ConstantName:
55
49
  # Not all trivial readers/writers can be defined with attr_* methods
56
50
  TrivialAccessors:
57
51
  Enabled: false
52
+
53
+ # Allow empty lines around body
54
+ EmptyLinesAroundBody:
55
+ Enabled: false
@@ -1,14 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'ice_nine'
4
- require 'thread_safe'
4
+ require 'memoizable'
5
5
 
6
6
  # Allows objects to be made immutable
7
7
  module Adamantium
8
8
 
9
- # Storage for memoized methods
10
- Memory = Class.new(ThreadSafe::Hash)
11
-
12
9
  # Defaults to less strict defaults
13
10
  module Flat
14
11
 
@@ -17,7 +14,6 @@ module Adamantium
17
14
  # @return [Freezer::Flat]
18
15
  #
19
16
  # @api private
20
- #
21
17
  def freezer
22
18
  Freezer::Flat
23
19
  end
@@ -31,8 +27,10 @@ module Adamantium
31
27
  # @api private
32
28
  def self.included(descendant)
33
29
  super
34
- descendant.send(:include, Adamantium)
35
- descendant.extend(self)
30
+ descendant.instance_exec(self) do |mod|
31
+ include Adamantium
32
+ extend mod
33
+ end
36
34
  end
37
35
  private_class_method :included
38
36
 
@@ -47,58 +45,22 @@ module Adamantium
47
45
  #
48
46
  # @api private
49
47
  def self.included(descendant)
50
- descendant.extend ModuleMethods
51
- descendant.extend ClassMethods if descendant.kind_of?(Class)
52
- self
53
- end
54
-
55
- # Freeze the object
56
- #
57
- # @example
58
- # object.freeze # object is now frozen
59
- #
60
- # @return [Object]
61
- #
62
- # @api public
63
- def freeze
64
- memory # initialize memory
65
48
  super
49
+ descendant.class_eval do
50
+ include Memoizable
51
+ extend ModuleMethods
52
+ extend ClassMethods if kind_of?(Class)
53
+ end
66
54
  end
55
+ private_class_method :included
67
56
 
68
- # Get the memoized value for a method
69
- #
70
- # @example
71
- # hash = object.memoized(:hash)
72
- #
73
- # @param [Symbol] name
74
- # the method name
57
+ # Alias to the original dup method
75
58
  #
76
59
  # @return [Object]
77
60
  #
78
- # @api public
79
- def memoized(name)
80
- memory[name]
81
- end
82
-
83
- # Sets a memoized value for a method
84
- #
85
- # @example
86
- # object.memoize(:hash, 12345)
87
- #
88
- # @param [Symbol] name
89
- # the method name
90
- # @param [Object] value
91
- # the value to memoize
92
- #
93
- # @return [self]
94
- #
95
- # @api public
96
- def memoize(name, value)
97
- unless memory.key?(name)
98
- store_memory(name, freeze_object(value))
99
- end
100
- self
101
- end
61
+ # @api private
62
+ alias_method :__adamantium_dup__, :dup
63
+ private :__adamantium_dup__
102
64
 
103
65
  # A noop #dup for immutable objects
104
66
  #
@@ -112,57 +74,34 @@ module Adamantium
112
74
  self
113
75
  end
114
76
 
115
- private
116
-
117
- # The memoized method results
118
- #
119
- # @return [Hash]
120
- #
121
- # @api private
122
- def memory
123
- @__memory ||= Memory.new
124
- end
77
+ protected
125
78
 
126
- # Freeze object
127
- #
128
- # @param [Object] object
129
- # an object to be frozen
79
+ # Transform the object with the provided block
130
80
  #
131
81
  # @return [Object]
132
82
  #
133
- # @api private
134
- def freeze_object(object)
135
- freezer.call(object)
136
- end
137
-
138
- # Return class level freezer
139
- #
140
- # @return [#call]
141
- #
142
- # @api private
143
- def freezer
144
- self.class.freezer
83
+ # @api public
84
+ def transform(&block)
85
+ copy = __adamantium_dup__
86
+ copy.instance_eval(&block)
87
+ self.class.freezer.freeze(copy)
145
88
  end
146
89
 
147
- # Store the value in memory
90
+ # Transform the object with the provided block if the condition is false
148
91
  #
149
- # @param [Symbol] name
150
- # the method name
151
- # @param [Object] value
152
- # the value to memoize
92
+ # @param [Boolean] condition
153
93
  #
154
- # @return [self]
155
- #
156
- # @return [value]
94
+ # @return [Object]
157
95
  #
158
- # @api private
159
- def store_memory(name, value)
160
- memory[name] = value
96
+ # @api public
97
+ def transform_unless(condition, &block)
98
+ condition ? self : transform(&block)
161
99
  end
162
100
 
163
- end # module Adamantium
101
+ end # Adamantium
164
102
 
165
103
  require 'adamantium/module_methods'
166
104
  require 'adamantium/class_methods'
167
105
  require 'adamantium/freezer'
168
106
  require 'adamantium/mutable'
107
+ require 'adamantium/version'
@@ -17,5 +17,5 @@ module Adamantium
17
17
  freezer.freeze(super)
18
18
  end
19
19
 
20
- end # module ClassMethods
21
- end # module Adamantium
20
+ end # ClassMethods
21
+ end # Adamantium
@@ -80,7 +80,7 @@ module Adamantium
80
80
  #
81
81
  # @api private
82
82
  def self.freeze(value)
83
- IceNine.deep_freeze(value)
83
+ IceNine.deep_freeze!(value)
84
84
  end
85
85
 
86
86
  public_class_method :call
@@ -94,6 +94,12 @@ module Adamantium
94
94
  # Error raised when memoizer options contain unknown keys
95
95
  class OptionError < RuntimeError; end
96
96
 
97
+ @freezers = {
98
+ noop: Noop,
99
+ deep: Deep,
100
+ flat: Flat,
101
+ }.freeze
102
+
97
103
  # Return freezer for name
98
104
  #
99
105
  # @param [Symbol] name
@@ -103,12 +109,8 @@ module Adamantium
103
109
  #
104
110
  # @api private
105
111
  def self.get(name)
106
- case name
107
- when :noop then Noop
108
- when :deep then Deep
109
- when :flat then Flat
110
- else
111
- raise UnknownFreezerError, "Freezer with name #{name.inspect} is unknown"
112
+ @freezers.fetch(name) do
113
+ fail UnknownFreezerError, "Freezer with name #{name.inspect} is unknown"
112
114
  end
113
115
  end
114
116
 
@@ -128,7 +130,7 @@ module Adamantium
128
130
  def self.parse(options)
129
131
  keys = options.keys - [:freezer]
130
132
  unless keys.empty?
131
- raise OptionError, "Unknown option key(s) for memoizer #{keys.inspect}"
133
+ fail OptionError, "Unknown option key(s) for memoizer #{keys.inspect}"
132
134
  end
133
135
  get(options.fetch(:freezer)) if options.key?(:freezer)
134
136
  end
@@ -5,25 +5,11 @@ module Adamantium
5
5
  # Methods mixed in to adamantium modules
6
6
  module ModuleMethods
7
7
 
8
- # Hook called when module is included
9
- #
10
- # @param [Module] mod
11
- # the module including ModuleMethods
12
- #
13
- # @return [self]
14
- #
15
- # @api private
16
- def included(mod)
17
- Adamantium.included(mod)
18
- self
19
- end
20
-
21
8
  # Return default deep freezer
22
9
  #
23
10
  # @return [Freezer::Deep]
24
11
  #
25
12
  # @api private
26
- #
27
13
  def freezer
28
14
  Freezer::Deep
29
15
  end
@@ -46,135 +32,35 @@ module Adamantium
46
32
  self
47
33
  end
48
34
 
49
- # Test if an instance method is memoized
50
- #
51
- # @example
52
- # class Foo
53
- # include Adamantium
54
- #
55
- # def bar
56
- # end
57
- # memoize :bar
58
- #
59
- # end
60
- #
61
- # Foo.memoized?(:bar) # true
62
- # Foo.memoized?(:baz) # false, does not care if method acutally exists
63
- #
64
- # @param [Symbol] name
65
- #
66
- # @return [true]
67
- # if method is memoized
68
- #
69
- # @return [false]
70
- # otherwise
71
- #
72
- # @api private
73
- #
74
- def memoized?(name)
75
- memoized_methods.key?(name)
76
- end
35
+ private
77
36
 
78
- # Return original instance method
79
- #
80
- # @example
81
- #
82
- # class Foo
83
- # include Adamantium
84
- #
85
- # def bar
86
- # end
87
- # memoize :bar
88
- #
89
- # end
90
- #
91
- # Foo.original_instance_method(:bar) #=> UnboundMethod, where source_location still points to original!
92
- #
93
- # @param [Symbol] name
94
- #
95
- # @return [UnboundMethod]
96
- # if method was memoized before
37
+ # Hook called when module is included
97
38
  #
98
- # @raise [ArgumentError]
99
- # otherwise
39
+ # @param [Module] descendant
40
+ # the module including ModuleMethods
100
41
  #
101
- # @api public
42
+ # @return [self]
102
43
  #
103
- def original_instance_method(name)
104
- memoized_methods[name]
44
+ # @api private
45
+ def included(descendant)
46
+ super
47
+ descendant.module_eval { include Adamantium }
105
48
  end
106
49
 
107
- private
108
-
109
50
  # Memoize the named method
110
51
  #
111
- # @param [#to_s] method_name
52
+ # @param [Symbol] method_name
112
53
  # a method name to memoize
113
54
  # @param [#call] freezer
114
- # a freezer for memoized values
55
+ # a callable object to freeze the value
115
56
  #
116
57
  # @return [undefined]
117
58
  #
118
59
  # @api private
119
60
  def memoize_method(method_name, freezer)
120
- method = instance_method(method_name)
121
- if method.arity.nonzero?
122
- raise ArgumentError, 'Cannot memoize method with nonzero arity'
123
- end
124
- memoized_methods[method_name] = method
125
- visibility = method_visibility(method_name)
126
- define_memoize_method(method, freezer)
127
- send(visibility, method_name)
128
- end
129
-
130
- # Return original method registry
131
- #
132
- # @return [Hash<Symbol, UnboundMethod>]
133
- #
134
- # @api private
135
- #
136
- def memoized_methods
137
- @memoized_methods ||= ThreadSafe::Hash.new do |_, name|
138
- raise ArgumentError, "No method #{name.inspect} was memoized"
139
- end
140
- end
141
-
142
- # Define a memoized method that delegates to the original method
143
- #
144
- # @param [UnboundMethod] method
145
- # the method to memoize
146
- # @param [#call] freezer
147
- # a freezer for memoized values
148
- #
149
- # @return [undefined]
150
- #
151
- # @api private
152
- def define_memoize_method(method, freezer)
153
- method_name = method.name.to_sym
154
- undef_method(method_name)
155
- define_method(method_name) do ||
156
- memory.fetch(method_name) do
157
- value = method.bind(self).call
158
- frozen = freezer.call(value)
159
- store_memory(method_name, frozen)
160
- end
161
- end
162
- end
163
-
164
- # Return the method visibility of a method
165
- #
166
- # @param [String, Symbol] method
167
- # the name of the method
168
- #
169
- # @return [Symbol]
170
- #
171
- # @api private
172
- def method_visibility(method)
173
- if private_method_defined?(method) then :private
174
- elsif protected_method_defined?(method) then :protected
175
- else :public
176
- end
61
+ memoized_methods[method_name] = Memoizable::MethodBuilder
62
+ .new(self, method_name, freezer).call
177
63
  end
178
64
 
179
- end # module ModuleMethods
180
- end # module Adamantium
65
+ end # ModuleMethods
66
+ end # Adamantium
@@ -3,6 +3,6 @@
3
3
  module Adamantium
4
4
 
5
5
  # Gem version
6
- VERSION = '0.1.0'.freeze
6
+ VERSION = '0.2.0'.freeze
7
7
 
8
- end # module Adamantium
8
+ end # Adamantium
@@ -12,9 +12,12 @@ if ENV['COVERAGE'] == 'true'
12
12
  ]
13
13
 
14
14
  SimpleCov.start do
15
- command_name 'spec:unit'
16
- add_filter 'config'
17
- add_filter 'spec'
15
+ command_name 'spec:unit'
16
+
17
+ add_filter 'config'
18
+ add_filter 'spec'
19
+ add_filter 'vendor'
20
+
18
21
  minimum_coverage 100
19
22
  end
20
23
  end
@@ -4,6 +4,8 @@ module AdamantiumSpecs
4
4
  class Object
5
5
  include Adamantium
6
6
 
7
+ public :transform, :transform_unless
8
+
7
9
  def argumented(foo)
8
10
  end
9
11
 
@@ -15,6 +17,10 @@ module AdamantiumSpecs
15
17
  caller
16
18
  end
17
19
 
20
+ def eql?(other)
21
+ kind_of?(other.class)
22
+ end
23
+
18
24
  protected
19
25
 
20
26
  def protected_method
@@ -22,12 +22,6 @@ describe Adamantium, '#freeze' do
22
22
  .from(false)
23
23
  .to(true)
24
24
  end
25
-
26
- it 'sets a memoization instance variable' do
27
- expect(object).to_not be_instance_variable_defined(:@__memory)
28
- subject
29
- expect(object.instance_variable_get(:@__memory)).to be_instance_of(Adamantium::Memory)
30
- end
31
25
  end
32
26
 
33
27
  context 'with a frozen object' do
@@ -38,14 +32,5 @@ describe Adamantium, '#freeze' do
38
32
  it 'does not change the frozen state of the object' do
39
33
  expect { subject }.to_not change(object, :frozen?)
40
34
  end
41
-
42
- it 'does not change the memoization instance variable' do
43
- expect { subject }.to_not change { object.instance_variable_get(:@__memory) }
44
- end
45
-
46
- it 'does not set an instance variable for memoization' do
47
- expect(object.instance_variable_get(:@__memory)).to be_instance_of(Adamantium::Memory)
48
- subject
49
- end
50
35
  end
51
36
  end
@@ -9,7 +9,7 @@ describe Adamantium::Freezer::Deep, '.freeze' do
9
9
  let(:value) { double('Value') }
10
10
 
11
11
  it 'should deep freeze value' do
12
- IceNine.should_receive(:deep_freeze).with(value).and_return(value)
12
+ IceNine.should_receive(:deep_freeze!).with(value).and_return(value)
13
13
  should be(value)
14
14
  end
15
15
  end
@@ -4,7 +4,7 @@ require 'spec_helper'
4
4
  require File.expand_path('../fixtures/classes', __FILE__)
5
5
 
6
6
  describe Adamantium, '#memoize' do
7
- subject { object.memoize(method, value) }
7
+ subject { object.memoize(method => value) }
8
8
 
9
9
  let(:described_class) { Class.new(AdamantiumSpecs::Object) }
10
10
  let(:object) { described_class.new }
@@ -14,33 +14,12 @@ describe Adamantium, '#memoize' do
14
14
  described_class.memoize(method)
15
15
  end
16
16
 
17
- context 'when the value is frozen' do
18
- let(:value) { String.new.freeze }
19
-
20
- it 'sets the memoized value for the method to the value' do
21
- subject
22
- expect(object.send(method)).to be(value)
23
- end
24
-
25
- it 'creates a method that returns a frozen value' do
26
- subject
27
- expect(object.send(method)).to be_frozen
28
- end
29
-
30
- it_should_behave_like 'a command method'
31
- end
32
-
33
- context 'when the value is not frozen' do
17
+ context 'when the method is not memoized' do
34
18
  let(:value) { String.new }
35
19
 
36
20
  it 'sets the memoized value for the method to the value' do
37
21
  subject
38
- expect(object.send(method)).to eql(value)
39
- end
40
-
41
- it 'creates a method that returns a frozen value' do
42
- subject
43
- expect(object.send(method)).to be_frozen
22
+ expect(object.send(method)).to be(value)
44
23
  end
45
24
 
46
25
  it_should_behave_like 'a command method'
@@ -51,13 +30,11 @@ describe Adamantium, '#memoize' do
51
30
  let(:original) { nil }
52
31
 
53
32
  before do
54
- object.memoize(method, original)
33
+ object.memoize(method => original)
55
34
  end
56
35
 
57
- it 'does not change the value' do
58
- expect { subject }.to_not change { object.send(method) }
36
+ it 'raises an exception' do
37
+ expect { subject }.to raise_error(ArgumentError)
59
38
  end
60
-
61
- it_should_behave_like 'a command method'
62
39
  end
63
40
  end
@@ -1,16 +1,40 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
- require File.expand_path('../../fixtures/classes', __FILE__)
5
4
 
6
5
  describe Adamantium::ModuleMethods, '#included' do
7
- subject { object.included(object) }
6
+ subject { descendant.instance_exec(object) { |mod| include mod } }
8
7
 
9
- let(:object) { AdamantiumSpecs::Object }
8
+ let(:object) { Module.new.extend(described_class) }
9
+ let(:descendant) { Class.new }
10
+ let(:superclass) { Module }
10
11
 
11
12
  before do
12
- Adamantium.should_receive(:included).with(object).and_return(Adamantium)
13
+ # Prevent Module.included from being called through inheritance
14
+ Adamantium.stub(:included)
13
15
  end
14
16
 
15
- it_should_behave_like 'a command method'
17
+ around do |example|
18
+ # Restore included method after each example
19
+ superclass.class_eval do
20
+ alias_method :original_included, :included
21
+ example.call
22
+ undef_method :included
23
+ alias_method :included, :original_included
24
+ end
25
+ end
26
+
27
+ it 'delegates to the superclass #included method' do
28
+ # This is the most succinct approach I could think of to test whether the
29
+ # superclass#included method is called. All of the built-in rspec helpers
30
+ # did not seem to work for this.
31
+ included = false
32
+ superclass.class_eval { define_method(:included) { |_| included = true } }
33
+ expect { subject }.to change { included }.from(false).to(true)
34
+ end
35
+
36
+ it 'includes Adamantium into the descendant' do
37
+ subject
38
+ expect(descendant.included_modules).to include(Adamantium)
39
+ end
16
40
  end
@@ -9,19 +9,17 @@ shared_examples_for 'memoizes method' do
9
9
  instance = object.new
10
10
  expect(instance.send(method)).to be(instance.send(method))
11
11
  end
12
+ end
12
13
 
13
- it 'creates a method that returns a same value' do
14
- subject
15
- instance = object.new
16
- expect(instance.send(method)).to be(instance.send(method))
17
- end
18
-
14
+ shared_examples_for 'wraps original method' do
19
15
  it 'creates a method with an arity of 0' do
20
16
  subject
21
17
  expect(object.new.method(method).arity).to be_zero
22
18
  end
23
19
 
24
20
  context 'when the initializer calls the memoized method' do
21
+ it_should_behave_like 'memoizes method'
22
+
25
23
  before do
26
24
  method = self.method
27
25
  object.send(:define_method, :initialize) { send(method) }
@@ -31,11 +29,6 @@ shared_examples_for 'memoizes method' do
31
29
  subject
32
30
  expect { object.new }.to_not raise_error
33
31
  end
34
-
35
- it 'memoizes the methdod inside the initializer' do
36
- subject
37
- expect(object.new.memoized(method)).to_not be_nil
38
- end
39
32
  end
40
33
  end
41
34
 
@@ -56,7 +49,7 @@ describe Adamantium::ModuleMethods, '#memoize' do
56
49
  let(:method) { :argumented }
57
50
 
58
51
  it 'should raise error' do
59
- expect { subject }.to raise_error(ArgumentError, 'Cannot memoize method with nonzero arity')
52
+ expect { subject }.to raise_error(ArgumentError, "Cannot memoize #{object}#argumented, its arity is 1")
60
53
  end
61
54
  end
62
55
 
@@ -65,7 +58,7 @@ describe Adamantium::ModuleMethods, '#memoize' do
65
58
  let(:options) { { freezer: :noop } }
66
59
 
67
60
  it_should_behave_like 'a command method'
68
- it_should_behave_like 'memoizes method'
61
+ it_should_behave_like 'wraps original method'
69
62
 
70
63
  it 'is still a public method' do
71
64
  should be_public_method_defined(method)
@@ -82,6 +75,7 @@ describe Adamantium::ModuleMethods, '#memoize' do
82
75
 
83
76
  it_should_behave_like 'a command method'
84
77
  it_should_behave_like 'memoizes method'
78
+ it_should_behave_like 'wraps original method'
85
79
 
86
80
  it 'creates a method that returns a frozen value' do
87
81
  subject
@@ -94,6 +88,7 @@ describe Adamantium::ModuleMethods, '#memoize' do
94
88
 
95
89
  it_should_behave_like 'a command method'
96
90
  it_should_behave_like 'memoizes method'
91
+ it_should_behave_like 'wraps original method'
97
92
 
98
93
  it 'is still a public method' do
99
94
  should be_public_method_defined(method)
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require File.expand_path('../fixtures/classes', __FILE__)
5
+
6
+ describe Adamantium, '#transform' do
7
+ let(:object) { described_class.new }
8
+ let(:described_class) { AdamantiumSpecs::Object }
9
+
10
+ it 'returns a copy of the object' do
11
+ transformed = object.transform {}
12
+ expect(transformed).to_not be(object)
13
+ expect(transformed).to eql(object)
14
+ end
15
+
16
+ it 'freezes the copy' do
17
+ expect(object.transform {}).to be_frozen
18
+ end
19
+
20
+ it 'yields the copy to the block' do
21
+ expect { |block| object.transform(&block) }
22
+ .to yield_with_args(described_class)
23
+ end
24
+
25
+ it 'evaluates the block within the context of the copy' do
26
+ copy = nil
27
+ expect(object.transform { copy = self }).to be(copy)
28
+ end
29
+
30
+ it 'evaluates the block with an unfrozen copy' do
31
+ frozen_in_block = nil
32
+ expect { object.transform { frozen_in_block = frozen? } }
33
+ .to change { frozen_in_block }.from(nil).to(false)
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require File.expand_path('../fixtures/classes', __FILE__)
5
+
6
+ describe Adamantium, '#transform_unless' do
7
+ let(:object) { described_class.new }
8
+ let(:described_class) { AdamantiumSpecs::Object }
9
+
10
+ context 'when the condition is true' do
11
+ let(:condition) { true }
12
+
13
+ it 'does not evaluate the block' do
14
+ expect { |block| object.transform_unless(condition, &block) }
15
+ .not_to yield_control
16
+ end
17
+
18
+ it 'returns the object' do
19
+ expect(object.transform_unless(condition) {}).to be(object)
20
+ end
21
+ end
22
+
23
+ context 'when the condition is false' do
24
+ let(:condition) { false }
25
+
26
+ it 'evaluates the block' do
27
+ expect { |block| object.transform_unless(condition, &block) }
28
+ .to yield_control
29
+ end
30
+
31
+ it 'returns a copy of the object' do
32
+ transformed = object.transform_unless(condition) {}
33
+ expect(transformed).to_not be(object)
34
+ expect(transformed).to eql(object)
35
+ end
36
+ end
37
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adamantium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Kubb
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-18 00:00:00.000000000 Z
12
+ date: 2014-01-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ice_nine
@@ -17,48 +17,48 @@ dependencies:
17
17
  requirements:
18
18
  - - ~>
19
19
  - !ruby/object:Gem::Version
20
- version: '0.9'
20
+ version: 0.11.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
- version: '0.9'
27
+ version: 0.11.0
28
28
  - !ruby/object:Gem::Dependency
29
- name: thread_safe
29
+ name: memoizable
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ~>
33
33
  - !ruby/object:Gem::Version
34
- version: 0.1.2
34
+ version: 0.4.0
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ~>
40
40
  - !ruby/object:Gem::Version
41
- version: 0.1.2
41
+ version: 0.4.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: bundler
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ~>
47
47
  - !ruby/object:Gem::Version
48
- version: '1.3'
49
- - - ! '>='
48
+ version: '1.5'
49
+ - - '>='
50
50
  - !ruby/object:Gem::Version
51
- version: 1.3.5
51
+ version: 1.5.2
52
52
  type: :development
53
53
  prerelease: false
54
54
  version_requirements: !ruby/object:Gem::Requirement
55
55
  requirements:
56
56
  - - ~>
57
57
  - !ruby/object:Gem::Version
58
- version: '1.3'
59
- - - ! '>='
58
+ version: '1.5'
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.3.5
61
+ version: 1.5.2
62
62
  description: Immutable extensions to objects
63
63
  email:
64
64
  - dan.kubb@gmail.com
@@ -73,6 +73,7 @@ extra_rdoc_files:
73
73
  files:
74
74
  - .gitignore
75
75
  - .rspec
76
+ - .rubocop.yml
76
77
  - .ruby-gemset
77
78
  - .travis.yml
78
79
  - CONTRIBUTING.md
@@ -103,7 +104,6 @@ files:
103
104
  - spec/rcov.opts
104
105
  - spec/spec_helper.rb
105
106
  - spec/support/config_alias.rb
106
- - spec/unit/adamantium/class_methods/included_spec.rb
107
107
  - spec/unit/adamantium/class_methods/new_spec.rb
108
108
  - spec/unit/adamantium/dup_spec.rb
109
109
  - spec/unit/adamantium/fixtures/classes.rb
@@ -117,14 +117,14 @@ files:
117
117
  - spec/unit/adamantium/freezer/flat/class_methods/call_spec.rb
118
118
  - spec/unit/adamantium/freezer/flat/class_methods/freeze_spec.rb
119
119
  - spec/unit/adamantium/memoize_spec.rb
120
- - spec/unit/adamantium/memoized_spec.rb
121
120
  - spec/unit/adamantium/module_methods/freezer_spec.rb
122
121
  - spec/unit/adamantium/module_methods/included_spec.rb
123
122
  - spec/unit/adamantium/module_methods/memoize_spec.rb
124
123
  - spec/unit/adamantium/module_methods/memoized_predicate_spec.rb
125
- - spec/unit/adamantium/module_methods/original_instance_method_spec.rb
126
124
  - spec/unit/adamantium/mutable/freeze_spec.rb
127
125
  - spec/unit/adamantium/mutable/frozen_predicate_spec.rb
126
+ - spec/unit/adamantium/transform_spec.rb
127
+ - spec/unit/adamantium/transform_unless_spec.rb
128
128
  homepage: https://github.com/dkubb/adamantium
129
129
  licenses:
130
130
  - MIT
@@ -135,23 +135,22 @@ require_paths:
135
135
  - lib
136
136
  required_ruby_version: !ruby/object:Gem::Requirement
137
137
  requirements:
138
- - - ! '>='
138
+ - - '>='
139
139
  - !ruby/object:Gem::Version
140
140
  version: '0'
141
141
  required_rubygems_version: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ! '>='
143
+ - - '>='
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
146
  requirements: []
147
147
  rubyforge_project:
148
- rubygems_version: 2.0.6
148
+ rubygems_version: 2.1.11
149
149
  signing_key:
150
150
  specification_version: 4
151
151
  summary: Immutable extensions to objects
152
152
  test_files:
153
153
  - spec/integration/adamantium_spec.rb
154
- - spec/unit/adamantium/class_methods/included_spec.rb
155
154
  - spec/unit/adamantium/class_methods/new_spec.rb
156
155
  - spec/unit/adamantium/dup_spec.rb
157
156
  - spec/unit/adamantium/fixtures/classes.rb
@@ -165,12 +164,12 @@ test_files:
165
164
  - spec/unit/adamantium/freezer/flat/class_methods/call_spec.rb
166
165
  - spec/unit/adamantium/freezer/flat/class_methods/freeze_spec.rb
167
166
  - spec/unit/adamantium/memoize_spec.rb
168
- - spec/unit/adamantium/memoized_spec.rb
169
167
  - spec/unit/adamantium/module_methods/freezer_spec.rb
170
168
  - spec/unit/adamantium/module_methods/included_spec.rb
171
169
  - spec/unit/adamantium/module_methods/memoize_spec.rb
172
170
  - spec/unit/adamantium/module_methods/memoized_predicate_spec.rb
173
- - spec/unit/adamantium/module_methods/original_instance_method_spec.rb
174
171
  - spec/unit/adamantium/mutable/freeze_spec.rb
175
172
  - spec/unit/adamantium/mutable/frozen_predicate_spec.rb
173
+ - spec/unit/adamantium/transform_spec.rb
174
+ - spec/unit/adamantium/transform_unless_spec.rb
176
175
  has_rdoc:
@@ -1,40 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Adamantium, '.included' do
6
- let(:object) { described_class }
7
-
8
- subject { object.included(target) }
9
-
10
- let(:included_modules) do
11
- target.singleton_class.included_modules
12
- end
13
-
14
- before { subject }
15
-
16
- context 'when target is a module' do
17
- let(:target) { Module.new }
18
-
19
- it_should_behave_like 'a command method'
20
-
21
- it 'includes Adamantium::ModuleMethods' do
22
- expect(included_modules).to include(Adamantium::ModuleMethods)
23
- end
24
-
25
- it 'does not include Adamantium::ClassMethods' do
26
- expect(included_modules).to_not include(Adamantium::ClassMethods)
27
- end
28
- end
29
-
30
- context 'when target is a class' do
31
- let(:target) { Class.new }
32
-
33
- it 'includes Adamantium::{Class,Module}Methods' do
34
- expect(included_modules).to include(Adamantium::ModuleMethods)
35
- expect(included_modules).to include(Adamantium::ClassMethods)
36
- end
37
-
38
- it_should_behave_like 'a command method'
39
- end
40
- end
@@ -1,29 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
- require File.expand_path('../fixtures/classes', __FILE__)
5
-
6
- describe Adamantium, '#memoized' do
7
- subject { object.memoized(method) }
8
-
9
- let(:described_class) { Class.new(AdamantiumSpecs::Object) }
10
- let(:method) { :test }
11
- let(:value) { String.new.freeze }
12
- let(:object) { described_class.new }
13
-
14
- before do
15
- described_class.memoize(method)
16
- end
17
-
18
- context 'when a method is memoized' do
19
- before do
20
- object.memoize(method, value)
21
- end
22
-
23
- it { should equal(value) }
24
- end
25
-
26
- context 'when a method is not memoized' do
27
- it { should be_nil }
28
- end
29
- end
@@ -1,36 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Adamantium::ModuleMethods, '#original_instance_method' do
6
- subject { object.original_instance_method(name).source_location }
7
-
8
- let(:object) do
9
- Class.new do
10
- include Adamantium
11
-
12
- def foo; end
13
-
14
- const_set(:ORIGINAL, instance_method(:foo).source_location)
15
-
16
- memoize :foo
17
- end
18
- end
19
-
20
- context 'when the method was memoized' do
21
- let(:name) { :foo }
22
-
23
- it 'returns the original method' do
24
- should eql(object::ORIGINAL)
25
- end
26
- end
27
-
28
- context 'when the method was not memoized' do
29
- let(:name) { :bar }
30
-
31
- it 'raises an exception' do
32
- expect { subject }
33
- .to raise_error(ArgumentError, 'No method :bar was memoized')
34
- end
35
- end
36
- end