anima 0.1.1 → 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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fdedbf4864bb7044d72c9f6e4ad63c1b364419ab
4
- data.tar.gz: 3a320c5eade913ddf3c3e2139f16f4e077a474d6
3
+ metadata.gz: 537a7e2e192c0d4b7519c1299b12bec430145e1f
4
+ data.tar.gz: 2ca3528ae56ef4f7ab304f9a394121ba74f20f28
5
5
  SHA512:
6
- metadata.gz: 8f30d533e039382d8eba7ba5b0386d86db400b9c61b4658e821c01fb5078c6f05df340f8077b5f74a2d872a39d5b104bfa87511ae9bdcefd3d680a74790dc8c2
7
- data.tar.gz: da76f7fe9694cb76ee9c0d401e3a360cbcef3ffee4d1b043117e50888271ba23baad4b4f4f908519f14851432401dc85b1e8a0cff16f005936e187827e58c735
6
+ metadata.gz: d989083d89deabafa011dbd874f1f90eab12f5efe36a8e1a472c70dfdbf061109e3786146b11cd59a3d3b4158e6f8187342c494fbc71fbc0f7f2b6de6fe237cb
7
+ data.tar.gz: 3874ed4c1a4454eee07b86d45dd3ddd718db57afded1332bee13b17a89e87d68ddb74ae8af227071272a1ee701933c724a350c32b17422fddf98c9e83ff9dd55
@@ -0,0 +1,6 @@
1
+ AllCops:
2
+ Includes:
3
+ - 'Gemfile'
4
+ Excludes:
5
+ - 'Gemfile.devtools'
6
+ - 'vendor/**'
@@ -1,11 +1,25 @@
1
1
  language: ruby
2
- script: 'bundle exec rake ci'
2
+ cache: bundler
3
+ bundler_args: --without yard guard benchmarks
4
+ script: "bundle exec rake ci:metrics"
3
5
  rvm:
4
6
  - 1.9.3
5
7
  - 2.0.0
6
- - jruby-19mode
7
- - jruby-head
8
- - rbx-19mode
8
+ - 2.1.0-rc1
9
+ - ruby-head
10
+ - rbx
11
+ matrix:
12
+ include:
13
+ - rvm: jruby-19mode
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-head
18
+ env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov
19
+ allow_failures:
20
+ - rvm: 2.1.0-rc1
21
+ - rvm: ruby-head
22
+ fast_finish: true
9
23
  notifications:
10
24
  irc:
11
25
  channels:
@@ -1,3 +1,18 @@
1
+ # v0.2.0 2014-01-13
2
+
3
+ Breaking changes:
4
+
5
+ * Remove AnimaInfectedClass.attributes_hash(instance)
6
+ * Replace with AnimaInfectedClass#to_h
7
+
8
+ # v0.1.1 2013-09-08
9
+
10
+ * [change] Refactor internals.
11
+
12
+ # v0.1.0 2013-09-08
13
+
14
+ * [change] Update dependencies
15
+
1
16
  # v0.0.6 2013-02-18
2
17
 
3
18
  * [add] Support for updates via Anima::Update mixin
data/Gemfile CHANGED
@@ -1,6 +1,11 @@
1
+ # encoding: utf-8
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
5
- gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
6
- eval File.read('Gemfile.devtools')
7
+ group :development, :test do
8
+ gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
9
+ end
10
+
11
+ eval_gemfile 'Gemfile.devtools'
@@ -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.2.4'
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'
40
+ gem 'rubocop', '~> 0.16.0'
41
+ gem 'simplecov', '~> 0.8.2'
39
42
  gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
40
43
 
44
+ platforms :mri do
45
+ gem 'mutant', '~> 0.3.4'
46
+ end
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.10'
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
@@ -5,7 +5,7 @@ anima
5
5
  [![Dependency Status](https://gemnasium.com/mbj/anima.png)](https://gemnasium.com/mbj/anima)
6
6
  [![Code Climate](https://codeclimate.com/github/mbj/anima.png)](https://codeclimate.com/github/mbj/anima)
7
7
 
8
- Simple library to declare read only attributes on value-objects that are initialized via attributes hash.
8
+ Simple library to declare read only attributes on value-objects that are initialized via attributes hash.
9
9
 
10
10
  Installation
11
11
  ------------
@@ -59,13 +59,15 @@ class Person
59
59
  end
60
60
 
61
61
  d = b.update(
62
- :salutation => 'Mrs',
62
+ :salutation => 'Mrs',
63
63
  :firstname => 'Sue',
64
64
  )
65
65
 
66
66
  # It returns copies, no inplace modification
67
67
  d.equal?(b) # => false
68
68
 
69
+ # Hash representation
70
+ d.to_h # => { :salutation => 'Mrs', :firstname => 'Sue' }
69
71
  ```
70
72
 
71
73
  Credits
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
1
  require 'devtools'
2
2
  Devtools.init_rake_tasks
3
+
4
+ Rake.application.load_imports
5
+ task('metrics:mutant').clear
6
+
7
+ namespace :metrics do
8
+ task :mutant => :coverage do
9
+ $stderr.puts 'Anima is a dependency of mutant and zombification is currently defunkt :('
10
+ end
11
+ end
@@ -1,12 +1,12 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'anima'
5
- s.version = '0.1.1'
5
+ s.version = '0.2.0'
6
6
 
7
7
  s.authors = ['Markus Schirp']
8
8
  s.email = 'mbj@schirp-dso.com'
9
- s.summary = 'Attributes for Plain Old Ruby Objects Experiment'
9
+ s.summary = 'Initialize object attributes via attributes hash'
10
10
  s.homepage = 'http://github.com/mbj/anima'
11
11
  s.license = 'MIT'
12
12
 
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.require_paths = %w(lib)
16
16
  s.extra_rdoc_files = %w(README.md)
17
17
 
18
- s.add_dependency('adamantium', '~> 0.1.0')
19
- s.add_dependency('equalizer', '~> 0.0.7')
20
- s.add_dependency('abstract_type', '~> 0.0.6')
18
+ s.add_dependency('adamantium', '~> 0.1')
19
+ s.add_dependency('equalizer', '~> 0.0.8')
20
+ s.add_dependency('abstract_type', '~> 0.0.7')
21
21
  end
@@ -0,0 +1,6 @@
1
+ ---
2
+ ruby:
3
+ version: 2.0.0-p353
4
+ test:
5
+ override:
6
+ - bundle exec rake ci
@@ -1,3 +1,3 @@
1
1
  ---
2
- threshold: 7
3
- total_score: 41
2
+ threshold: 6
3
+ total_score: 44
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 12.8
2
+ threshold: 9.2
@@ -8,7 +8,7 @@ UncommunicativeParameterName:
8
8
  - !ruby/regexp /[0-9]$/
9
9
  - !ruby/regexp /[A-Z]/
10
10
  TooManyMethods:
11
- max_methods: 13
11
+ max_methods: 9
12
12
  exclude: []
13
13
  enabled: true
14
14
  max_instance_variables: 2
@@ -49,6 +49,8 @@ NestedIterators:
49
49
  ignore_iterators: []
50
50
  exclude:
51
51
  - Anima::Attribute#define_reader # 2 levels
52
+ - Anima::Builder#define_anima_method # 2 levels
53
+ - Anima::Builder#define_attribute_readers # 2 levels
52
54
  enabled: true
53
55
  max_allowed_nesting: 1
54
56
  TooManyStatements:
@@ -1,12 +1,4 @@
1
- AllCops:
2
- Includes:
3
- - '../**/*.rake'
4
- - 'Gemfile'
5
- - 'Gemfile.devtools'
6
- - 'mutant.gemspec'
7
- Excludes:
8
- - '**/vendor/**'
9
- - '**/benchmarks/**'
1
+ inherit_from: ../.rubocop.yml
10
2
 
11
3
  # Avoid parameter lists longer than five parameters.
12
4
  ParameterLists:
@@ -31,7 +23,7 @@ CollectionMethods:
31
23
  # sections of code and visually separate them. When the keyword is at the same
32
24
  # level I think it sort of blends in with the def keywords and makes it harder
33
25
  # to scan the code and see where the sections are.
34
- AccessControl:
26
+ AccessModifierIndentation:
35
27
  Enabled: false
36
28
 
37
29
  MethodLength:
@@ -83,3 +75,7 @@ TrivialAccessors:
83
75
  # And also have a differend opinion here
84
76
  AndOr:
85
77
  Enabled: false
78
+
79
+ # Allow empty lines around body
80
+ EmptyLinesAroundBody:
81
+ Enabled: false
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'adamantium'
2
4
  require 'equalizer'
3
5
  require 'abstract_type'
@@ -8,7 +10,7 @@ class Anima < Module
8
10
 
9
11
  # Return names
10
12
  #
11
- # @return [AttriuteSet]
13
+ # @return [AttributeSet]
12
14
  #
13
15
  # @api private
14
16
  #
@@ -21,35 +23,35 @@ class Anima < Module
21
23
  # @api private
22
24
  #
23
25
  def initialize(*names)
24
- @attributes = names.uniq.map { |name| Attribute.new(name) }.freeze
26
+ @attributes = names.uniq.map(&Attribute.method(:new)).freeze
25
27
  end
26
28
 
27
- # Return new anima with attributes removed
29
+ # Return new anima with attributes added
28
30
  #
29
31
  # @return [Anima]
30
32
  #
31
33
  # @example
32
- # anima = Anima.new(:foo)
34
+ # anima = Anima.new(:foo, :bar)
33
35
  # anima.add(:foo) # equals Anima.new(:foo, :bar)
34
36
  #
35
- # @api public
37
+ # @api private
36
38
  #
37
- def remove(*names)
38
- new(attribute_names - names)
39
+ def add(*names)
40
+ new(attribute_names + names)
39
41
  end
40
42
 
41
- # Return new anima with attributes added
43
+ # Return new anima with attributes removed
42
44
  #
43
45
  # @return [Anima]
44
46
  #
45
47
  # @example
46
- # anima = Anima.new(:foo, :bar)
48
+ # anima = Anima.new(:foo)
47
49
  # anima.remove(:bar) # equals Anima.new(:foo)
48
50
  #
49
- # @api private
51
+ # @api public
50
52
  #
51
- def add(*names)
52
- new(attribute_names + names)
53
+ def remove(*names)
54
+ new(attribute_names - names)
53
55
  end
54
56
 
55
57
  # Return attributes hash for instance
@@ -88,20 +90,14 @@ class Anima < Module
88
90
  # @api private
89
91
  #
90
92
  def initialize_instance(object, attribute_hash)
93
+ assert_known_attributes(object, attribute_hash)
91
94
  attributes.each do |attribute|
92
95
  attribute.load(object, attribute_hash)
93
96
  end
94
-
95
- overflow = attribute_hash.keys - attribute_names
96
-
97
- unless overflow.empty?
98
- raise Error::Unknown.new(object.class, overflow)
99
- end
100
-
101
97
  self
102
98
  end
103
99
 
104
- private
100
+ private
105
101
 
106
102
  # Hook called when module is included
107
103
  #
@@ -111,97 +107,46 @@ private
111
107
  #
112
108
  # @api private
113
109
  #
114
- def included(scope)
115
- define_anima_method(scope)
116
- define_initializer(scope)
117
- define_attribute_readers(scope)
118
- define_attribute_hash_reader(scope)
119
- define_equalizer(scope)
110
+ def included(descendant)
111
+ Builder.call(self, descendant)
120
112
  end
121
113
 
122
- # Return new instance
114
+ # Fail unless keys in +attribute_hash+ matches #attribute_names
123
115
  #
124
- # @param [Enumerable<Symbol>] attributes
125
- #
126
- # @return [Anima]
127
- #
128
- # @api private
129
- #
130
- def new(attributes)
131
- self.class.new(*attributes)
132
- end
133
-
134
- # Define anima method on scope
116
+ # @param [Object] object
117
+ # the object being initialized
135
118
  #
136
- # @param [Class, Module] scope
119
+ # @param [Hash] attribute_hash
120
+ # the attributes to initialize +object+ with
137
121
  #
138
122
  # @return [undefined]
139
123
  #
140
- # @api private
141
- #
142
- def define_anima_method(scope)
143
- anima = self
144
-
145
- scope.define_singleton_method(:anima) do
146
- anima
147
- end
148
- end
149
-
150
- # Define equalizer on scope
151
- #
152
- # @param [Class, Module] scope
153
- #
154
- # @return [undefined]
124
+ # @raise [Error::Unknown]
155
125
  #
156
126
  # @api private
157
- #
158
- def define_equalizer(scope)
159
- scope.send(:include, Equalizer.new(*attribute_names))
160
- end
127
+ def assert_known_attributes(object, attribute_hash)
128
+ overflow = attribute_hash.keys - attribute_names
161
129
 
162
- # Define attribute readers
163
- #
164
- # @param [Class, Module] scope
165
- #
166
- # @return [undefined]
167
- #
168
- # @api private
169
- #
170
- def define_attribute_readers(scope)
171
- attributes.each do |attribute|
172
- attribute.define_reader(scope)
130
+ if overflow.any?
131
+ fail Error::Unknown.new(object, overflow)
173
132
  end
174
133
  end
175
134
 
176
- # Define initializer
135
+ # Return new instance
177
136
  #
178
- # @param [Class, Module] scope
137
+ # @param [Enumerable<Symbol>] attributes
179
138
  #
180
- # @return [undefined]
139
+ # @return [Anima]
181
140
  #
182
141
  # @api private
183
142
  #
184
- def define_initializer(scope)
185
- scope.send(:define_method, :initialize) do |attributes|
186
- self.class.anima.initialize_instance(self, attributes)
187
- end
143
+ def new(attributes)
144
+ self.class.new(*attributes)
188
145
  end
189
146
 
190
- # Define attribute hash reader
191
- #
192
- # @param [Class, Module] scope
193
- #
194
- # @return [undefined]
195
- #
196
- # @api private
197
- #
198
- def define_attribute_hash_reader(scope)
199
- scope.define_singleton_method(:attributes_hash) do |object|
200
- anima.attributes_hash(object)
201
- end
202
- end
203
- end
147
+ end # Anima
204
148
 
149
+ require 'anima/builder'
205
150
  require 'anima/error'
206
151
  require 'anima/attribute'
207
152
  require 'anima/update'
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  class Anima
2
4
 
3
5
  # An attribute
@@ -11,7 +13,7 @@ class Anima
11
13
  # @api private
12
14
  #
13
15
  def initialize(name)
14
- @name = name
16
+ @name, @instance_variable_name = name, :"@#{name}"
15
17
  end
16
18
 
17
19
  # Return attribute name
@@ -32,10 +34,8 @@ class Anima
32
34
  # @api private
33
35
  #
34
36
  def load(object, attributes)
35
- attribute_name = name
36
-
37
- value = attributes.fetch(attribute_name) do
38
- raise Error::Missing.new(object.class, attribute_name)
37
+ value = attributes.fetch(name) do |attribute_name|
38
+ fail Error::Missing.new(object, attribute_name)
39
39
  end
40
40
 
41
41
  set(object, value)
@@ -63,33 +63,8 @@ class Anima
63
63
  # @api private
64
64
  #
65
65
  def set(object, value)
66
- object.instance_variable_set(instance_variable_name, value)
67
-
68
- self
69
- end
70
-
71
- # Return instance variable name
72
- #
73
- # @return [Symbol]
74
- # returns @ prefixed name
75
- #
76
- # @api private
77
- #
78
- def instance_variable_name
79
- :"@#{name}"
80
- end
81
- memoize :instance_variable_name
66
+ object.instance_variable_set(@instance_variable_name, value)
82
67
 
83
- # Define reader
84
- #
85
- # @param [Class, Module] scope
86
- #
87
- # @return [self]
88
- #
89
- # @api private
90
- #
91
- def define_reader(scope)
92
- scope.send(:attr_reader, name)
93
68
  self
94
69
  end
95
70
 
@@ -0,0 +1,130 @@
1
+ # encoding: utf-8
2
+
3
+ class Anima
4
+
5
+ # Builds an anima infected class
6
+ class Builder
7
+
8
+ # Static instance methods for anima infected classes
9
+ module Methods
10
+ # Initialize an anima infected object
11
+ #
12
+ # @param [#to_h] attributes
13
+ # a hash that matches anima defined attributes
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api public
18
+ def initialize(attributes)
19
+ self.class.anima.initialize_instance(self, attributes)
20
+ end
21
+
22
+ # Return a hash representation of an anima infected object
23
+ #
24
+ # @return [Hash]
25
+ #
26
+ # @api public
27
+ def to_h
28
+ self.class.anima.attributes_hash(self)
29
+ end
30
+ end # Methods
31
+
32
+ include Adamantium::Flat
33
+
34
+ # Infect +descendant+ with anima
35
+ #
36
+ # @param [Anima] anima
37
+ # the anima instance used for infection
38
+ #
39
+ # @param [Class, Module] descendant
40
+ # the object to infect
41
+ #
42
+ # @return [undefined]
43
+ #
44
+ # @api private
45
+ def self.call(anima, descendant)
46
+ new(anima, descendant).call
47
+ end
48
+
49
+ # Initialize a new instance
50
+ #
51
+ # @param [Anima] anima
52
+ # the anima instance used for infection
53
+ #
54
+ # @param [Class, Module] descendant
55
+ # the object to infect
56
+ #
57
+ # @return [undefined]
58
+ #
59
+ # @api private
60
+ def initialize(anima, descendant)
61
+ @anima = anima
62
+ @names = anima.attribute_names
63
+ @descendant = descendant
64
+ end
65
+
66
+ # Infect the instance with anima
67
+ #
68
+ # @return [undefined]
69
+ #
70
+ # @api private
71
+ def call
72
+ define_equalizer
73
+ define_anima_method
74
+ define_attribute_readers
75
+ descendant_exec do
76
+ include Methods
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ # Define equalizer
83
+ #
84
+ # @return [undefined]
85
+ #
86
+ # @api private
87
+ def define_equalizer
88
+ descendant_exec(@names) do |names|
89
+ include Equalizer.new(*names)
90
+ end
91
+ end
92
+
93
+ # Define anima method
94
+ #
95
+ # @return [undefined]
96
+ #
97
+ # @api private
98
+ def define_anima_method
99
+ descendant_exec(@anima) do |anima|
100
+ define_singleton_method(:anima) { anima }
101
+ end
102
+ end
103
+
104
+ # Define attribute readers
105
+ #
106
+ # @return [undefined]
107
+ #
108
+ # @api private
109
+ def define_attribute_readers
110
+ descendant_exec(@names) do |names|
111
+ attr_reader(*names)
112
+ end
113
+ end
114
+
115
+ # Deduplicate instance_exec inside descendant's scope
116
+ #
117
+ # @param [*] *args
118
+ # arguments to pass to instance_exec
119
+ #
120
+ # @param [Proc] &block
121
+ # the block to eval
122
+ #
123
+ # @return [undefined]
124
+ #
125
+ # @api private
126
+ def descendant_exec(*args, &block)
127
+ @descendant.instance_exec(*args, &block)
128
+ end
129
+ end # Builder
130
+ end # Anima
@@ -1,29 +1,39 @@
1
+ # encoding: utf-8
2
+
1
3
  class Anima
2
4
 
3
5
  # Abstract base class for anima errors
4
6
  class Error < RuntimeError
7
+
8
+ # Error for unknown attributes
9
+ class Unknown < self
10
+ end
11
+
12
+ # Error for missing attributes
13
+ class Missing < self
14
+ end
15
+
5
16
  include AbstractType
6
17
 
18
+ DOUBLE_COLON = '::'.freeze
19
+
7
20
  # Initialize object
8
21
  #
9
- # @param [Class] model
22
+ # @param [Object] object
10
23
  # @param [Enumerable<Symbol>] names
11
24
  #
12
25
  # @return [undefined]
13
26
  #
14
27
  # @api private
15
28
  #
16
- def initialize(model, names)
17
- super("#{self.class.name.split('::').last} attribute(s) #{names.inspect} for #{model.name}")
29
+ def initialize(object, names)
30
+ super("#{name} attribute(s) #{names.inspect} for #{object.class}")
18
31
  end
19
32
 
20
- # Error for unknown attributes
21
- class Unknown < self
22
- end
33
+ private
23
34
 
24
- # Error for missing attributes
25
- class Missing < self
35
+ def name
36
+ self.class.name.split(DOUBLE_COLON).last
26
37
  end
27
-
28
- end
29
- end
38
+ end # Error
39
+ end # Anima
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  class Anima
2
4
  # Module for mixin in update functionallity to anima infected clases
3
5
  module Update
@@ -21,8 +23,7 @@ class Anima
21
23
  # @api private
22
24
  #
23
25
  def update(attributes)
24
- klass = self.class
25
- klass.new(klass.attributes_hash(self).merge(attributes))
26
+ self.class.new(to_h.update(attributes))
26
27
  end
27
28
 
28
29
  end # Update
@@ -1,19 +1,15 @@
1
- require 'spec_helper'
1
+ # encoding: utf-8
2
2
 
3
- describe Anima, 'simple integration' do
4
- subject { class_under_test.new(attributes) }
3
+ require 'spec_helper'
5
4
 
6
- let(:class_under_test) do
7
- Class.new do
8
- include Anima.new(:firstname, :lastname)
5
+ class TestClass
6
+ include Anima.new(:firstname, :lastname)
7
+ end
9
8
 
10
- def self.name
11
- 'TestClass'
12
- end
13
- end
14
- end
9
+ describe Anima, 'simple integration' do
10
+ subject { TestClass.new(attributes) }
15
11
 
16
- context 'when instanciated with all attributes' do
12
+ context 'when instantiated with all attributes' do
17
13
  let(:attributes) do
18
14
  {
19
15
  firstname: 'Markus',
@@ -25,7 +21,7 @@ describe Anima, 'simple integration' do
25
21
  its(:lastname) { should eql('Schirp') }
26
22
  end
27
23
 
28
- context 'with instanciated with extra attributes' do
24
+ context 'with instantiated with extra attributes' do
29
25
  let(:attributes) do
30
26
  {
31
27
  firstname: 'Markus',
@@ -42,7 +38,7 @@ describe Anima, 'simple integration' do
42
38
  end
43
39
  end
44
40
 
45
- context 'when instanciated with missing attribute' do
41
+ context 'when instantiated with missing attributes' do
46
42
 
47
43
  let(:attributes) { {} }
48
44
 
@@ -1,29 +1,10 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Anima::Attribute do
4
6
  let(:object) { described_class.new(:foo) }
5
7
 
6
- describe '#define_reader' do
7
- subject { object.define_reader(target_class) }
8
-
9
- let(:target_class) do
10
- Class.new do
11
- def initialize(foo)
12
- @foo = foo
13
- end
14
- end
15
- end
16
-
17
- let(:value) { double('Value') }
18
-
19
- it 'should create a reader' do
20
- instance = target_class.new(value)
21
- -> { subject }.should change { instance.respond_to?(:foo) }.from(false).to(true)
22
- end
23
-
24
- it_should_behave_like 'a command method'
25
- end
26
-
27
8
  describe '#get' do
28
9
  subject { object.get(target) }
29
10
 
@@ -45,14 +26,6 @@ describe Anima::Attribute do
45
26
  end
46
27
  end
47
28
 
48
- describe '#instance_variable_name' do
49
- subject { Anima::Attribute.new(:foo).instance_variable_name }
50
-
51
- it { should be(:@foo) }
52
-
53
- it_should_behave_like 'an idempotent method'
54
- end
55
-
56
29
  describe '#load' do
57
30
  subject { object.load(target, attribute_hash) }
58
31
 
@@ -76,7 +49,7 @@ describe Anima::Attribute do
76
49
  let(:attribute_hash) { {} }
77
50
 
78
51
  it 'should raise error' do
79
- expect { subject }.to raise_error(Anima::Error::Missing, Anima::Error::Missing.new(target.class, :foo).message)
52
+ expect { subject }.to raise_error(Anima::Error::Missing, Anima::Error::Missing.new(target, :foo).message)
80
53
  end
81
54
  end
82
55
  end
@@ -1,15 +1,25 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Anima::Error, '#message' do
4
- let(:object) { described_class.new(klass, name) }
6
+ let(:object) { error.new(instance, name) }
7
+
8
+ let(:error) do
9
+ Class.new(described_class) do
10
+ def self.name
11
+ 'Test::Error'
12
+ end
13
+ end
14
+ end
5
15
 
6
16
  subject { object.message }
7
17
 
8
- let(:klass) { double(name: 'THE-CLASS-NAME') }
9
- let(:name) { 'THE-ATTRIBUTE-NAME' }
18
+ let(:instance) { Object.new }
19
+ let(:name) { 'foo' }
10
20
 
11
21
  it 'should return the message string' do
12
- should eql('Error attribute(s) "THE-ATTRIBUTE-NAME" for THE-CLASS-NAME')
22
+ should eql('Error attribute(s) "foo" for Object')
13
23
  end
14
24
 
15
25
  it_should_behave_like 'an idempotent method'
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Anima::Update, '#update' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Anima do
@@ -80,13 +82,14 @@ describe Anima do
80
82
  its(:foo) { should be(value) }
81
83
 
82
84
  it { should eql(instance_b) }
85
+ it { should_not eql(instance_c) }
83
86
  end
84
87
 
85
88
  context 'on singleton' do
86
89
  subject { target }
87
90
 
88
91
  it 'should define attribute hash reader' do
89
- target.attributes_hash(instance).should eql(foo: value)
92
+ instance.to_h.should eql(foo: value)
90
93
  end
91
94
 
92
95
  its(:anima) { should be(object) }
@@ -114,11 +117,11 @@ describe Anima do
114
117
  it_should_behave_like 'a command method'
115
118
  end
116
119
 
117
- context 'when extra key is missing in attribute hash' do
120
+ context 'when an extra key is present in attribute hash' do
118
121
  let(:attribute_hash) { { foo: foo, bar: bar, baz: double('Baz') } }
119
122
 
120
123
  it 'should raise error' do
121
- expect { subject }.to raise_error(Anima::Error::Unknown, Anima::Error::Unknown.new(target.class, [:baz]).message)
124
+ expect { subject }.to raise_error(Anima::Error::Unknown, Anima::Error::Unknown.new(target, [:baz]).message)
122
125
  end
123
126
  end
124
127
 
@@ -126,8 +129,37 @@ describe Anima do
126
129
  let(:attribute_hash) { { bar: bar } }
127
130
 
128
131
  it 'should raise error' do
129
- expect { subject }.to raise_error(Anima::Error::Missing, Anima::Error::Missing.new(target.class, :foo).message)
132
+ expect { subject }.to raise_error(Anima::Error::Missing, Anima::Error::Missing.new(target, :foo).message)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe 'using super in initialize' do
138
+ subject { klass.new }
139
+
140
+ let(:klass) do
141
+ Class.new do
142
+ include Anima.new(:foo)
143
+ def initialize(attributes = { foo: :bar })
144
+ super
145
+ end
130
146
  end
131
147
  end
148
+
149
+ its(:foo) { should eql(:bar) }
150
+ end
151
+
152
+ describe '#to_h on an anima infected instance' do
153
+ subject { instance.to_h }
154
+
155
+ let(:instance) { klass.new(params) }
156
+ let(:params) { Hash[foo: :bar] }
157
+ let(:klass) do
158
+ Class.new do
159
+ include Anima.new(:foo)
160
+ end
161
+ end
162
+
163
+ it { should eql(params) }
132
164
  end
133
165
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anima
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-11 00:00:00.000000000 Z
11
+ date: 2014-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: adamantium
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.0
19
+ version: '0.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.0
26
+ version: '0.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: equalizer
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: 0.0.7
33
+ version: 0.0.8
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: 0.0.7
40
+ version: 0.0.8
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: abstract_type
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: 0.0.6
47
+ version: 0.0.7
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: 0.0.6
54
+ version: 0.0.7
55
55
  description:
56
56
  email: mbj@schirp-dso.com
57
57
  executables: []
@@ -61,6 +61,7 @@ extra_rdoc_files:
61
61
  files:
62
62
  - .gitignore
63
63
  - .rspec
64
+ - .rubocop.yml
64
65
  - .travis.yml
65
66
  - Changelog.md
66
67
  - Gemfile
@@ -70,6 +71,7 @@ files:
70
71
  - Rakefile
71
72
  - TODO
72
73
  - anima.gemspec
74
+ - circle.yml
73
75
  - config/flay.yml
74
76
  - config/flog.yml
75
77
  - config/mutant.yml
@@ -79,6 +81,7 @@ files:
79
81
  - config/yardstick.yml
80
82
  - lib/anima.rb
81
83
  - lib/anima/attribute.rb
84
+ - lib/anima/builder.rb
82
85
  - lib/anima/error.rb
83
86
  - lib/anima/update.rb
84
87
  - spec/integration/simple_spec.rb
@@ -107,10 +110,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
110
  version: '0'
108
111
  requirements: []
109
112
  rubyforge_project:
110
- rubygems_version: 2.0.2
113
+ rubygems_version: 2.0.14
111
114
  signing_key:
112
115
  specification_version: 4
113
- summary: Attributes for Plain Old Ruby Objects Experiment
116
+ summary: Initialize object attributes via attributes hash
114
117
  test_files:
115
118
  - spec/integration/simple_spec.rb
116
119
  - spec/spec_helper.rb