minimapper 0.8.0 → 0.9.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.
- data/Gemfile +4 -1
- data/README.md +36 -5
- data/lib/minimapper/entity.rb +3 -3
- data/lib/minimapper/entity/convert.rb +2 -2
- data/lib/minimapper/entity/core.rb +12 -0
- data/lib/minimapper/entity/rails.rb +3 -2
- data/lib/minimapper/mapper.rb +5 -3
- data/lib/minimapper/version.rb +1 -1
- data/spec/support/shared_examples/mapper.rb +17 -3
- data/unit/entity/attributes_spec.rb +2 -2
- data/unit/entity/convert_spec.rb +11 -11
- data/unit/entity/rails_spec.rb +7 -6
- data/unit/repository_spec.rb +4 -4
- metadata +10 -4
data/Gemfile
CHANGED
@@ -2,7 +2,10 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# We don't require active_record to use minimapper, only to
|
4
4
|
# use minimapper/mapper/ar. We do require it for the tests though :)
|
5
|
-
|
5
|
+
#
|
6
|
+
# Also locked to below rails 4.0 as our specs use rails 3 features. Need to look into
|
7
|
+
# if there are any issues with rails 4.
|
8
|
+
gem "activerecord", "< 4.0"
|
6
9
|
gem "rspec"
|
7
10
|
|
8
11
|
platforms :ruby do
|
data/README.md
CHANGED
@@ -113,7 +113,7 @@ Repository = Minimapper::Repository.build({
|
|
113
113
|
|
114
114
|
user = User.new(:name => "Joe")
|
115
115
|
Repository.users.create(user)
|
116
|
-
p
|
116
|
+
p Repository.users.find(user.id).name # => Joe
|
117
117
|
Repository.users.delete_all
|
118
118
|
|
119
119
|
## Using ActiveModel validations
|
@@ -168,7 +168,7 @@ end
|
|
168
168
|
|
169
169
|
`entity_for` returns nil for nil.
|
170
170
|
|
171
|
-
|
171
|
+
`entity_for` and `entities_for` take an optional second argument if you want a different entity class than the mapper's:
|
172
172
|
|
173
173
|
```
|
174
174
|
class ProjectMapper < Minimapper::AR
|
@@ -186,15 +186,15 @@ If you specify type, Minimapper will only allow values of that type, or strings
|
|
186
186
|
The latter means that it can accept e.g. string integers directly from a form.
|
187
187
|
Minimapper aims to be much less of a form value parser than ActiveRecord, but we'll allow ourselves conveniences like this.
|
188
188
|
|
189
|
-
Supported types: Integer and DateTime
|
189
|
+
Supported types: Integer and DateTime.
|
190
190
|
|
191
191
|
``` ruby
|
192
192
|
class User
|
193
193
|
include Minimapper::Entity
|
194
|
-
attributes [ :profile_id,
|
194
|
+
attributes [ :profile_id, Integer ]
|
195
195
|
|
196
196
|
# Or for single attributes:
|
197
|
-
# attribute :profile_id,
|
197
|
+
# attribute :profile_id, Integer
|
198
198
|
end
|
199
199
|
|
200
200
|
User.new(:profile_id => "10").profile_id # => 10
|
@@ -226,6 +226,8 @@ User.new(:reminder_on => "2012-01-01").reminder # => #<Date: 2012-01-01 ...>
|
|
226
226
|
|
227
227
|
Minimapper only calls #convert on non-empty strings. When the value is blank or nil, the attribute is set to nil.
|
228
228
|
|
229
|
+
(FIXME? We're considering changing this so Minimapper core can only enforce type, and there's some `Minimapper::FormObject` mixin to parse string values.)
|
230
|
+
|
229
231
|
### Overriding attribute accessors
|
230
232
|
|
231
233
|
Attribute readers and writers are implemented so that you can override them with inheritance:
|
@@ -277,6 +279,35 @@ class ProjectMapper < Minimapper::AR
|
|
277
279
|
end
|
278
280
|
```
|
279
281
|
|
282
|
+
### Deletion
|
283
|
+
|
284
|
+
When you do `mapper.delete(entity)`, it will use [ActiveRecord's `delete`](http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-destroy), which means that no destroy callbacks or `:dependent` association options are honored.
|
285
|
+
|
286
|
+
(FIXME?: Should we support `destroy` instead or as well?)
|
287
|
+
|
288
|
+
### Exceptions and status 404
|
289
|
+
|
290
|
+
Code like `UserMapper.find(123)` will raise `Minimapper::EntityNotFound` if there's no such record.
|
291
|
+
|
292
|
+
Rails treats the similar `ActiveRecord::RecordNotFound` exception as a 404 error, using that status code with the error backtrace in development and test, and showing the 404 page in production.
|
293
|
+
|
294
|
+
If you want the same for Minimapper, you can add a `config/initializers/minimapper.rb` containing:
|
295
|
+
|
296
|
+
``` ruby
|
297
|
+
# For 404 status with the dev/test backtrace, and a 404 page in production.
|
298
|
+
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(
|
299
|
+
"Minimapper::EntityNotFound" => :not_found
|
300
|
+
)
|
301
|
+
```
|
302
|
+
|
303
|
+
You may also want to ignore those errors in your error logger. With [Honeybadger](https://www.honeybadger.io), you do:
|
304
|
+
|
305
|
+
``` ruby
|
306
|
+
Honeybadger.configure do |config|
|
307
|
+
config.ignore << "Minimapper::EntityNotFound"
|
308
|
+
end
|
309
|
+
```
|
310
|
+
|
280
311
|
### Custom entity class
|
281
312
|
|
282
313
|
[Minimapper::Entity](https://github.com/joakimk/minimapper/blob/master/lib/minimapper/entity.rb) adds some convenience methods for when a model is used within a Rails application. If you don't need that you can just include the core API from the [Minimapper::Entity::Core](https://github.com/joakimk/minimapper/blob/master/lib/minimapper/entity/core.rb) module (or implement your own version that behaves like [Minimapper::Entity::Core](https://github.com/joakimk/minimapper/blob/master/lib/minimapper/entity/core.rb)).
|
data/lib/minimapper/entity.rb
CHANGED
@@ -21,9 +21,9 @@ module Minimapper
|
|
21
21
|
klass.send(:include, Minimapper::Entity::Validation)
|
22
22
|
klass.send(:include, Minimapper::Entity::Rails)
|
23
23
|
klass.attributes(
|
24
|
-
[ :id,
|
25
|
-
[ :created_at,
|
26
|
-
[ :updated_at,
|
24
|
+
[ :id, Integer ],
|
25
|
+
[ :created_at, DateTime ],
|
26
|
+
[ :updated_at, DateTime ]
|
27
27
|
)
|
28
28
|
end
|
29
29
|
end
|
@@ -14,8 +14,8 @@ module Minimapper
|
|
14
14
|
@@converters[type] = converter
|
15
15
|
end
|
16
16
|
|
17
|
-
register_converter
|
18
|
-
register_converter
|
17
|
+
register_converter Integer, ToInteger.new
|
18
|
+
register_converter DateTime, ToDateTime.new
|
19
19
|
|
20
20
|
def to(type)
|
21
21
|
return nil if value != false && value.blank?
|
@@ -30,6 +30,18 @@ module Minimapper
|
|
30
30
|
@mapper_errors = list
|
31
31
|
end
|
32
32
|
|
33
|
+
def persisted?
|
34
|
+
@entity_is_persisted
|
35
|
+
end
|
36
|
+
|
37
|
+
def mark_as_persisted
|
38
|
+
@entity_is_persisted = true
|
39
|
+
end
|
40
|
+
|
41
|
+
def mark_as_not_persisted
|
42
|
+
@entity_is_persisted = false
|
43
|
+
end
|
44
|
+
|
33
45
|
private
|
34
46
|
|
35
47
|
def symbolize_keys(hash)
|
data/lib/minimapper/mapper.rb
CHANGED
@@ -14,6 +14,7 @@ module Minimapper
|
|
14
14
|
|
15
15
|
if entity.valid?
|
16
16
|
record.save!
|
17
|
+
entity.mark_as_persisted
|
17
18
|
entity.id = record.id
|
18
19
|
entity.id
|
19
20
|
else
|
@@ -67,7 +68,7 @@ module Minimapper
|
|
67
68
|
|
68
69
|
def delete(entity)
|
69
70
|
delete_by_id(entity.id)
|
70
|
-
entity.
|
71
|
+
entity.mark_as_not_persisted
|
71
72
|
end
|
72
73
|
|
73
74
|
def delete_by_id(id)
|
@@ -122,14 +123,15 @@ module Minimapper
|
|
122
123
|
raise(EntityNotFound, entity.inspect)
|
123
124
|
end
|
124
125
|
|
125
|
-
def entities_for(records)
|
126
|
-
records.map { |record| entity_for(record) }
|
126
|
+
def entities_for(records, klass = entity_class)
|
127
|
+
records.map { |record| entity_for(record, klass) }
|
127
128
|
end
|
128
129
|
|
129
130
|
def entity_for(record, klass = entity_class)
|
130
131
|
if record
|
131
132
|
entity = klass.new
|
132
133
|
entity.id = record.id
|
134
|
+
entity.mark_as_persisted
|
133
135
|
entity.attributes = record.attributes.symbolize_keys
|
134
136
|
|
135
137
|
if klass == entity_class
|
data/lib/minimapper/version.rb
CHANGED
@@ -18,6 +18,13 @@ shared_examples :mapper do
|
|
18
18
|
entity2.id.should == entity1.id + 1
|
19
19
|
end
|
20
20
|
|
21
|
+
it "marks the entity as persisted" do
|
22
|
+
entity1 = build_valid_entity
|
23
|
+
entity1.should_not be_persisted
|
24
|
+
mapper.create(entity1)
|
25
|
+
entity1.should be_persisted
|
26
|
+
end
|
27
|
+
|
21
28
|
it "returns the id" do
|
22
29
|
id = mapper.create(build_valid_entity)
|
23
30
|
id.should be_kind_of(Fixnum)
|
@@ -70,6 +77,13 @@ shared_examples :mapper do
|
|
70
77
|
found_entity = mapper.find(entity.id)
|
71
78
|
end
|
72
79
|
|
80
|
+
it "returns an entity marked as persisted" do
|
81
|
+
entity = build_valid_entity
|
82
|
+
mapper.create(entity)
|
83
|
+
found_entity = mapper.find(entity.id)
|
84
|
+
found_entity.should be_persisted
|
85
|
+
end
|
86
|
+
|
73
87
|
it "fails when an entity can not be found" do
|
74
88
|
lambda { mapper.find(-1) }.should raise_error(Minimapper::EntityNotFound)
|
75
89
|
end
|
@@ -228,12 +242,12 @@ shared_examples :mapper do
|
|
228
242
|
mapper.first.id.should_not == removed_entity_id
|
229
243
|
end
|
230
244
|
|
231
|
-
it "
|
245
|
+
it "marks the entity as no longer persisted" do
|
232
246
|
entity = build_valid_entity
|
233
247
|
mapper.create(entity)
|
234
|
-
entity.
|
248
|
+
entity.should be_persisted
|
235
249
|
mapper.delete(entity)
|
236
|
-
entity.
|
250
|
+
entity.should_not be_persisted
|
237
251
|
end
|
238
252
|
|
239
253
|
it "fails when the entity does not have an id" do
|
@@ -5,7 +5,7 @@ module Attribute
|
|
5
5
|
class User
|
6
6
|
include Minimapper::Entity::Core
|
7
7
|
include Minimapper::Entity::Attributes
|
8
|
-
attribute :id,
|
8
|
+
attribute :id, Integer
|
9
9
|
attribute :name
|
10
10
|
end
|
11
11
|
|
@@ -23,7 +23,7 @@ module Attribute
|
|
23
23
|
include Minimapper::Entity::Core
|
24
24
|
include Minimapper::Entity::Attributes
|
25
25
|
|
26
|
-
attribute :due_at,
|
26
|
+
attribute :due_at, DateTime
|
27
27
|
end
|
28
28
|
|
29
29
|
class OverridingUser
|
data/unit/entity/convert_spec.rb
CHANGED
@@ -1,34 +1,34 @@
|
|
1
1
|
require 'minimapper/entity/convert'
|
2
2
|
|
3
3
|
describe Minimapper::Entity::Convert do
|
4
|
-
describe "
|
4
|
+
describe "Integer" do
|
5
5
|
it "allows integers" do
|
6
|
-
described_class.new(10).to(
|
6
|
+
described_class.new(10).to(Integer).should == 10
|
7
7
|
end
|
8
8
|
|
9
9
|
it "converts strings into integers" do
|
10
|
-
described_class.new('10').to(
|
11
|
-
described_class.new(' 10 ').to(
|
10
|
+
described_class.new('10').to(Integer).should == 10
|
11
|
+
described_class.new(' 10 ').to(Integer).should == 10
|
12
12
|
end
|
13
13
|
|
14
14
|
it "makes it nil when it can't convert" do
|
15
|
-
described_class.new(' ').to(
|
16
|
-
described_class.new('garbage').to(
|
15
|
+
described_class.new(' ').to(Integer).should be_nil
|
16
|
+
described_class.new('garbage').to(Integer).should be_nil
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
describe "
|
20
|
+
describe "DateTime" do
|
21
21
|
it "allows DateTimes" do
|
22
|
-
described_class.new(DateTime.new(2013, 6, 1)).to(
|
22
|
+
described_class.new(DateTime.new(2013, 6, 1)).to(DateTime).should == DateTime.new(2013, 6, 1)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "converts datetime strings into datetimes" do
|
26
|
-
described_class.new('2012-01-01 20:57').to(
|
26
|
+
described_class.new('2012-01-01 20:57').to(DateTime).should == DateTime.new(2012, 01, 01, 20, 57)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "makes it nil when it can't convert" do
|
30
|
-
described_class.new(' ').to(
|
31
|
-
described_class.new('garbage').to(
|
30
|
+
described_class.new(' ').to(DateTime).should be_nil
|
31
|
+
described_class.new('garbage').to(DateTime).should be_nil
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
data/unit/entity/rails_spec.rb
CHANGED
@@ -9,20 +9,21 @@ end
|
|
9
9
|
describe Minimapper::Entity::Rails do
|
10
10
|
it "responds to new_record?" do
|
11
11
|
entity = RailsEntity.new
|
12
|
-
entity.should
|
13
|
-
entity.
|
14
|
-
entity.
|
12
|
+
entity.new_record?.should be_true
|
13
|
+
entity.mark_as_persisted
|
14
|
+
entity.new_record?.should be_false
|
15
15
|
end
|
16
16
|
|
17
|
-
it "
|
17
|
+
it "responds to to_model" do
|
18
18
|
entity = RailsEntity.new
|
19
19
|
entity.to_model.should == entity
|
20
20
|
end
|
21
21
|
|
22
22
|
it "responds to to_key" do
|
23
23
|
entity = RailsEntity.new
|
24
|
-
entity.to_key.should be_nil
|
25
24
|
entity.id = 5
|
25
|
+
entity.to_key.should be_nil
|
26
|
+
entity.mark_as_persisted
|
26
27
|
entity.to_key.should == [ 5 ]
|
27
28
|
end
|
28
29
|
|
@@ -37,7 +38,7 @@ describe Minimapper::Entity::Rails do
|
|
37
38
|
it "responds to persisted?" do
|
38
39
|
entity = RailsEntity.new
|
39
40
|
entity.should_not be_persisted
|
40
|
-
entity.
|
41
|
+
entity.mark_as_persisted
|
41
42
|
entity.should be_persisted
|
42
43
|
end
|
43
44
|
end
|
data/unit/repository_spec.rb
CHANGED
@@ -25,8 +25,8 @@ describe Minimapper::Repository, "self.build" do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it "does not leak between instances" do
|
28
|
-
mapper1 =
|
29
|
-
mapper2 =
|
28
|
+
mapper1 = double.as_null_object
|
29
|
+
mapper2 = double.as_null_object
|
30
30
|
repository1 = described_class.build(:projects => mapper1)
|
31
31
|
repository2 = described_class.build(:projects => mapper2)
|
32
32
|
repository1.projects.should == mapper1
|
@@ -36,8 +36,8 @@ end
|
|
36
36
|
|
37
37
|
describe Minimapper::Repository, "#delete_all!" do
|
38
38
|
it "removes all records by calling delete_all on all mappers" do
|
39
|
-
project_mapper =
|
40
|
-
user_mapper =
|
39
|
+
project_mapper = double.as_null_object
|
40
|
+
user_mapper = double.as_null_object
|
41
41
|
|
42
42
|
project_mapper.should_receive(:delete_all)
|
43
43
|
user_mapper.should_receive(:delete_all)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minimapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &70096190311420 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70096190311420
|
25
25
|
description: A minimalistic way of separating your models from ActiveRecord.
|
26
26
|
email:
|
27
27
|
- joakim.kolsjo@gmail.com
|
@@ -75,12 +75,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
75
|
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
hash: 2287659495149187599
|
78
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
82
|
none: false
|
80
83
|
requirements:
|
81
84
|
- - ! '>='
|
82
85
|
- !ruby/object:Gem::Version
|
83
86
|
version: '0'
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
hash: 2287659495149187599
|
84
90
|
requirements: []
|
85
91
|
rubyforge_project:
|
86
92
|
rubygems_version: 1.8.5
|