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 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
- gem "activerecord"
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 repository.users.find(user.id).name # => Joe
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
- It takes an optional second argument if you want a different entity class than the mapper's:
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 (`:integer` and `:date_time`).
189
+ Supported types: Integer and DateTime.
190
190
 
191
191
  ``` ruby
192
192
  class User
193
193
  include Minimapper::Entity
194
- attributes [ :profile_id, :integer ]
194
+ attributes [ :profile_id, Integer ]
195
195
 
196
196
  # Or for single attributes:
197
- # attribute :profile_id, :integer
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)).
@@ -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, :integer ],
25
- [ :created_at, :date_time ],
26
- [ :updated_at, :date_time ]
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 :integer, ToInteger.new
18
- register_converter :date_time, ToDateTime.new
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)
@@ -9,12 +9,13 @@ module Minimapper
9
9
  id
10
10
  end
11
11
 
12
+ # Implemented in core.
12
13
  def persisted?
13
- id
14
+ super
14
15
  end
15
16
 
16
17
  def new_record?
17
- !id
18
+ !persisted?
18
19
  end
19
20
 
20
21
  def to_model
@@ -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.id = nil
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
@@ -1,3 +1,3 @@
1
1
  module Minimapper
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -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 "clears the entity id" do
245
+ it "marks the entity as no longer persisted" do
232
246
  entity = build_valid_entity
233
247
  mapper.create(entity)
234
- entity.id.should_not be_nil
248
+ entity.should be_persisted
235
249
  mapper.delete(entity)
236
- entity.id.should be_nil
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, :integer
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, :date_time
26
+ attribute :due_at, DateTime
27
27
  end
28
28
 
29
29
  class OverridingUser
@@ -1,34 +1,34 @@
1
1
  require 'minimapper/entity/convert'
2
2
 
3
3
  describe Minimapper::Entity::Convert do
4
- describe ":integer" do
4
+ describe "Integer" do
5
5
  it "allows integers" do
6
- described_class.new(10).to(:integer).should == 10
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(:integer).should == 10
11
- described_class.new(' 10 ').to(:integer).should == 10
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(:integer).should be_nil
16
- described_class.new('garbage').to(:integer).should be_nil
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 ":date_time" do
20
+ describe "DateTime" do
21
21
  it "allows DateTimes" do
22
- described_class.new(DateTime.new(2013, 6, 1)).to(:date_time).should == DateTime.new(2013, 6, 1)
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(:date_time).should == DateTime.new(2012, 01, 01, 20, 57)
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(:date_time).should be_nil
31
- described_class.new('garbage').to(:date_time).should be_nil
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
 
@@ -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 be_new_record
13
- entity.id = 5
14
- entity.should_not be_new_record
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 "resonds to to_model" do
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.id = 5
41
+ entity.mark_as_persisted
41
42
  entity.should be_persisted
42
43
  end
43
44
  end
@@ -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 = mock.as_null_object
29
- mapper2 = mock.as_null_object
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 = mock.as_null_object
40
- user_mapper = mock.as_null_object
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.8.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-06-09 00:00:00.000000000 Z
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: &70270060752600 !ruby/object:Gem::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: *70270060752600
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