anima 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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