minimapper 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -123,9 +123,9 @@ p Repository.users.count # => 0
123
123
  p user.errors.full_messages # Name can't be blank
124
124
  ```
125
125
 
126
- ### Loading all the data you need before acting on it
126
+ ### Eager loading
127
127
 
128
- When using minimapper you generally want to load all data you need upfront whenever possible as you don't have lazy loading. We haven't gotten around to adding the inclusion syntax yet, but [it's quite simple to implement](https://gist.github.com/joakimk/5656945).
128
+ When using minimapper you don't have lazy loading. We haven't gotten around to adding the association-inclusion syntax yet, but [it's quite simple to implement](https://gist.github.com/joakimk/5656945).
129
129
 
130
130
  ### Uniqueness validations and other DB validations
131
131
 
@@ -267,8 +267,6 @@ For some discussion, [see this issue](https://github.com/joakimk/minimapper/issu
267
267
 
268
268
  This is called after any kind of find and can be used for things like loading associated data.
269
269
 
270
- The parameters to the after_find hook differs between mappers, for example the ActiveRecord mapper provides a record as the second argument. In practice this should not be a problem as each mapper class in an app only implements one type of mapper.
271
-
272
270
  ``` ruby
273
271
  class ProjectMapper < Minimapper::AR
274
272
  private
@@ -320,12 +318,6 @@ You need mysql and postgres installed (but they do not have to be running) to be
320
318
  5. Push to the branch (`git push origin my-new-feature`)
321
319
  6. Create new Pull Request
322
320
 
323
- ## Todo
324
-
325
- ### Next
326
-
327
- * Support default values for attributes (probably only using lambdas to avoid bugs).
328
-
329
321
  ## Credits and license
330
322
 
331
323
  By [Joakim Kolsjö](https://twitter.com/joakimk) under the MIT license:
@@ -3,62 +3,81 @@ require 'minimapper/entity/convert'
3
3
  module Minimapper
4
4
  module Entity
5
5
  module Attributes
6
- def attributes(*list)
7
- columns = add_columns(list)
8
-
9
- # By adding instance methods via an included module,
10
- # they become overridable with "super".
11
- unless @minimapper_instance_method_container
12
- @minimapper_instance_method_container = Module.new
13
- include @minimapper_instance_method_container
14
- end
6
+ def self.included(klass)
7
+ klass.extend ClassMethods
8
+ end
15
9
 
16
- columns.each do |column|
17
- define_reader(column)
18
- define_writer(column)
19
- end
10
+ def initialize(attributes = {})
11
+ self.attributes = attributes
20
12
  end
21
13
 
22
- def attribute(*opts)
23
- attributes [ *opts ]
14
+ def attributes=(new_attributes)
15
+ super(new_attributes)
16
+ new_attributes.each_pair { |name, value| self.send("#{name}=", value) }
24
17
  end
25
18
 
26
- # Compatibility with certain Rails plugins, like Traco.
27
- def column_names
28
- @entity_columns.map(&:name).map(&:to_s)
19
+ def normalize_attribute_value(value, type)
20
+ Convert.new(value).to(type)
29
21
  end
30
22
 
31
- private
23
+ module ClassMethods
24
+ def attributes(*list)
25
+ columns = add_columns(list)
32
26
 
33
- def add_columns(list)
34
- @entity_columns ||= []
35
- @entity_columns |= list.map { |data| Column.new(data) }
36
- end
27
+ # By adding instance methods via an included module,
28
+ # they become overridable with "super".
29
+ unless @minimapper_instance_method_container
30
+ @minimapper_instance_method_container = Module.new
31
+ include @minimapper_instance_method_container
32
+ end
37
33
 
38
- def define_reader(column)
39
- @minimapper_instance_method_container.module_eval do
40
- define_method(column.name) do
41
- attributes[column.name]
34
+ columns.each do |column|
35
+ define_reader(column)
36
+ define_writer(column)
42
37
  end
43
38
  end
44
- end
45
39
 
46
- def define_writer(column)
47
- @minimapper_instance_method_container.module_eval do
48
- define_method("#{column.name}=") do |value|
49
- attributes[column.name] = Convert.new(value).to(column.type)
40
+ def attribute(*opts)
41
+ attributes [ *opts ]
42
+ end
43
+
44
+ # Compatibility with certain Rails plugins, like Traco.
45
+ def column_names
46
+ @entity_columns.map(&:name).map(&:to_s)
47
+ end
48
+
49
+ private
50
+
51
+ def add_columns(list)
52
+ @entity_columns ||= []
53
+ @entity_columns |= list.map { |data| Column.new(data) }
54
+ end
55
+
56
+ def define_reader(column)
57
+ @minimapper_instance_method_container.module_eval do
58
+ define_method(column.name) do
59
+ attributes[column.name]
60
+ end
61
+ end
62
+ end
63
+
64
+ def define_writer(column)
65
+ @minimapper_instance_method_container.module_eval do
66
+ define_method("#{column.name}=") do |value|
67
+ attributes[column.name] = normalize_attribute_value(value, column.type)
68
+ end
50
69
  end
51
70
  end
52
- end
53
71
 
54
- class Column
55
- attr_reader :name, :type
72
+ class Column
73
+ attr_reader :name, :type
56
74
 
57
- def initialize(data)
58
- if data.is_a?(Array)
59
- @name, @type = data
60
- else
61
- @name = data
75
+ def initialize(data)
76
+ if data.is_a?(Array)
77
+ @name, @type = data
78
+ else
79
+ @name = data
80
+ end
62
81
  end
63
82
  end
64
83
  end
@@ -1,3 +1,4 @@
1
+ require 'active_support/core_ext'
1
2
  require 'minimapper/entity/convert/to_integer'
2
3
  require 'minimapper/entity/convert/to_date_time'
3
4
 
@@ -1,8 +1,8 @@
1
1
  # The core entity API required by minimapper. If your entity class implements
2
- # this API, it should work with the data mappers.
2
+ # this API, it should work with the mapper.
3
3
 
4
4
  # IMPORTANT: This module should only implement the minimal interface needed
5
- # to talk to the data mappers. If a method isn't used by the mappers it should
5
+ # to talk to the data mapper. If a method isn't used by the mapper it should
6
6
  # not be in this file.
7
7
 
8
8
  module Minimapper
@@ -1,35 +1,10 @@
1
- # Include this in your entity models for
1
+ # Include this in your entity classes for
2
2
  # Ruby on Rails conveniences, like being
3
3
  # able to use them in forms.
4
4
 
5
- require "active_model"
6
-
7
5
  module Minimapper
8
6
  module Entity
9
7
  module Rails
10
- def self.included(klass)
11
- klass.class_eval do
12
- extend ActiveModel::Naming
13
- include ActiveModel::Validations
14
-
15
- # Must be added after ActiveModel::Validations so our
16
- # validations can call ActiveModel's with `super`.
17
- include ValidationsWithMapperErrors
18
- end
19
- end
20
-
21
- module ValidationsWithMapperErrors
22
- def valid?
23
- super
24
-
25
- mapper_errors.each do |a, v|
26
- errors.add(a, v)
27
- end
28
-
29
- errors.empty?
30
- end
31
- end
32
-
33
8
  def to_param
34
9
  id
35
10
  end
@@ -0,0 +1,30 @@
1
+ require "active_model"
2
+
3
+ module Minimapper
4
+ module Entity
5
+ module Validation
6
+ def self.included(klass)
7
+ klass.class_eval do
8
+ extend ActiveModel::Naming
9
+ include ActiveModel::Validations
10
+
11
+ # Must be added after ActiveModel::Validations so our
12
+ # validations can call ActiveModel's with `super`.
13
+ include ValidationsWithMapperErrors
14
+ end
15
+ end
16
+
17
+ module ValidationsWithMapperErrors
18
+ def valid?
19
+ super
20
+
21
+ mapper_errors.each do |a, v|
22
+ errors.add(a, v)
23
+ end
24
+
25
+ errors.empty?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,21 +1,13 @@
1
1
  # Look at minimapper/entity/core for the required API.
2
2
  require 'minimapper/entity/core'
3
3
  require 'minimapper/entity/attributes'
4
+ require 'minimapper/entity/validation'
4
5
  require 'minimapper/entity/rails'
5
6
 
6
7
  module Minimapper
7
8
  module Entity
8
9
  include Minimapper::Entity::Core
9
10
 
10
- def initialize(attributes = {})
11
- self.attributes = attributes
12
- end
13
-
14
- def attributes=(new_attributes)
15
- super(new_attributes)
16
- new_attributes.each_pair { |name, value| self.send("#{name}=", value) }
17
- end
18
-
19
11
  def ==(other)
20
12
  super || (
21
13
  other.instance_of?(self.class) &&
@@ -25,8 +17,9 @@ module Minimapper
25
17
  end
26
18
 
27
19
  def self.included(klass)
20
+ klass.send(:include, Minimapper::Entity::Attributes)
21
+ klass.send(:include, Minimapper::Entity::Validation)
28
22
  klass.send(:include, Minimapper::Entity::Rails)
29
- klass.send(:extend, Minimapper::Entity::Attributes)
30
23
  klass.attributes(
31
24
  [ :id, :integer ],
32
25
  [ :created_at, :date_time ],
@@ -1,3 +1,3 @@
1
1
  module Minimapper
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -0,0 +1,140 @@
1
+ require 'minimapper/entity/core'
2
+ require 'minimapper/entity/attributes'
3
+
4
+ module Attribute
5
+ class User
6
+ include Minimapper::Entity::Core
7
+ include Minimapper::Entity::Attributes
8
+ attribute :id, :integer
9
+ attribute :name
10
+ end
11
+
12
+ class AgedUser < User
13
+ attributes :age
14
+ end
15
+
16
+ class Project
17
+ include Minimapper::Entity::Core
18
+ include Minimapper::Entity::Attributes
19
+ attributes :title
20
+ end
21
+
22
+ class Task
23
+ include Minimapper::Entity::Core
24
+ include Minimapper::Entity::Attributes
25
+
26
+ attribute :due_at, :date_time
27
+ end
28
+
29
+ class OverridingUser
30
+ include Minimapper::Entity::Core
31
+ include Minimapper::Entity::Attributes
32
+ attributes :name
33
+
34
+ def name
35
+ super.upcase
36
+ end
37
+
38
+ def name=(value)
39
+ super(value.strip)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe Minimapper::Entity::Attributes, "attributes without type" do
45
+ let(:entity_class) do
46
+ Class.new do
47
+ include Minimapper::Entity::Core
48
+ include Minimapper::Entity::Attributes
49
+ attribute :name
50
+ end
51
+ end
52
+
53
+ it "can be set and get with anything" do
54
+ user = entity_class.new
55
+ user.name = "Hello"
56
+ user.name.should == "Hello"
57
+ user.name = 5
58
+ user.name.should == 5
59
+ end
60
+ end
61
+
62
+ describe Minimapper::Entity::Attributes do
63
+ it "can access attributes set at construction time" do
64
+ entity = Attribute::User.new(:id => 5)
65
+ entity.id.should == 5
66
+ entity.attributes[:id].should == 5
67
+ end
68
+
69
+ it "can access attributes set through a hash" do
70
+ entity = Attribute::User.new
71
+ entity.attributes = { :id => 5 }
72
+ entity.id.should == 5
73
+ entity.attributes = { "id" => 8 }
74
+ entity.id.should == 8
75
+ end
76
+
77
+ it "converts typed attributes" do
78
+ entity = Attribute::User.new
79
+ entity.id = "10"
80
+ entity.id.should == 10
81
+ entity.attributes = { :id => "15" }
82
+ entity.id.should == 15
83
+ end
84
+
85
+ it "can use single line type declarations" do
86
+ task = Attribute::Task.new(:due_at => "2012-01-01 15:00")
87
+ task.due_at.should == DateTime.parse("2012-01-01 15:00")
88
+ end
89
+
90
+ it "sets blank values to nil" do
91
+ user = Attribute::User.new
92
+ user.name = " "
93
+ user.name.should be_nil
94
+ end
95
+
96
+ it "symbolizes keys" do
97
+ entity = Attribute::User.new
98
+ entity.attributes = { "id" => "15" }
99
+ entity.attributes[:id].should == 15
100
+ end
101
+
102
+ it "inherits attributes" do
103
+ user = Attribute::AgedUser.new
104
+ user.name = "Name"
105
+ user.age = 123
106
+ user.name.should == "Name"
107
+ user.age.should == 123
108
+ end
109
+
110
+ it "is possible to override attribute readers with inheritance" do
111
+ user = Attribute::OverridingUser.new
112
+ user.name = "pelle"
113
+ user.name.should == "PELLE"
114
+ end
115
+
116
+ it "is possible to override attribute writers with inheritance" do
117
+ user = Attribute::OverridingUser.new
118
+ user.name = " 123 "
119
+ user.name.should == "123"
120
+ end
121
+ end
122
+
123
+ describe Minimapper::Entity::Attributes, "attributes" do
124
+ it "returns the attributes" do
125
+ entity = Attribute::User.new(:id => 5)
126
+ time = Time.now
127
+ entity.attributes.should == { :id => 5 }
128
+ end
129
+ end
130
+
131
+ describe Minimapper::Entity::Attributes, "self.column_names" do
132
+ it "returns all attributes as strings" do
133
+ # used by some rails plugins
134
+ Attribute::User.column_names.should == [ "id", "name" ]
135
+ end
136
+
137
+ it "does not leak between different models" do
138
+ Attribute::Project.column_names.should == [ "title" ]
139
+ end
140
+ end
@@ -1,5 +1,4 @@
1
1
  require 'minimapper/entity/convert'
2
- require 'active_support/core_ext'
3
2
 
4
3
  describe Minimapper::Entity::Convert do
5
4
  describe ":integer" do
@@ -1,12 +1,9 @@
1
- require 'minimapper/entity/rails'
2
1
  require 'minimapper/entity/core'
2
+ require 'minimapper/entity/rails'
3
3
 
4
4
  class RailsEntity
5
5
  include Minimapper::Entity::Core
6
6
  include Minimapper::Entity::Rails
7
-
8
- attr_accessor :name
9
- validates :name, :presence => true
10
7
  end
11
8
 
12
9
  describe Minimapper::Entity::Rails do
@@ -43,22 +40,4 @@ describe Minimapper::Entity::Rails do
43
40
  entity.id = 5
44
41
  entity.should be_persisted
45
42
  end
46
-
47
- it "includes active model validations" do
48
- entity = RailsEntity.new
49
- entity.should_not be_valid
50
- entity.name = "Joe"
51
- entity.should be_valid
52
- end
53
-
54
- describe "#mapper_errors=" do
55
- it "adds an error to the errors collection" do
56
- entity = RailsEntity.new
57
- entity.name = "Joe"
58
- entity.should be_valid
59
- entity.mapper_errors = [ [:name, "must be unique"] ]
60
- entity.should_not be_valid
61
- entity.errors[:name].should == ["must be unique"]
62
- end
63
- end
64
43
  end
@@ -0,0 +1,30 @@
1
+ require 'minimapper/entity/core'
2
+ require 'minimapper/entity/validation'
3
+
4
+ class ValidatableEntity
5
+ include Minimapper::Entity::Core
6
+ include Minimapper::Entity::Validation
7
+
8
+ attr_accessor :name
9
+ validates :name, :presence => true
10
+ end
11
+
12
+ describe Minimapper::Entity::Validation do
13
+ it "includes active model validations" do
14
+ entity = ValidatableEntity.new
15
+ entity.should_not be_valid
16
+ entity.name = "Joe"
17
+ entity.should be_valid
18
+ end
19
+
20
+ describe "#mapper_errors=" do
21
+ it "adds an error to the errors collection" do
22
+ entity = ValidatableEntity.new
23
+ entity.name = "Joe"
24
+ entity.should be_valid
25
+ entity.mapper_errors = [ [:name, "must be unique"] ]
26
+ entity.should_not be_valid
27
+ entity.errors[:name].should == ["must be unique"]
28
+ end
29
+ end
30
+ end
data/unit/entity_spec.rb CHANGED
@@ -1,45 +1,24 @@
1
1
  require 'minimapper/entity'
2
2
 
3
- class TestEntity
4
- include Minimapper::Entity
5
- end
6
-
7
3
  class TestUser
8
4
  include Minimapper::Entity
9
5
  attributes :name
10
6
  end
11
7
 
12
- class TestAgedUser < TestUser
13
- attributes :age
14
- end
15
-
16
8
  class TestProject
17
9
  include Minimapper::Entity
18
10
  attributes :title
19
11
  end
20
12
 
21
- class TestTask
22
- include Minimapper::Entity
23
-
24
- attribute :due_at, :date_time
25
- end
26
-
27
- class OverridingTestUser
28
- include Minimapper::Entity
29
- attributes :name
30
-
31
- def name
32
- super.upcase
33
- end
34
-
35
- def name=(value)
36
- super(value.strip)
13
+ describe Minimapper::Entity do
14
+ let(:entity_class) do
15
+ Class.new do
16
+ include Minimapper::Entity
17
+ end
37
18
  end
38
- end
39
19
 
40
- describe Minimapper::Entity do
41
20
  it "handles base attributes" do
42
- entity = TestEntity.new
21
+ entity = entity_class.new
43
22
 
44
23
  entity.id = 5
45
24
  entity.id.should == 5
@@ -51,95 +30,6 @@ describe Minimapper::Entity do
51
30
  entity.updated_at = time
52
31
  entity.updated_at.should == time
53
32
  end
54
-
55
- it "can access attributes set at construction time" do
56
- entity = TestUser.new(:id => 5)
57
- entity.id.should == 5
58
- entity.attributes[:id].should == 5
59
- end
60
-
61
- it "can access attributes set through a hash" do
62
- entity = TestUser.new
63
- entity.attributes = { :id => 5 }
64
- entity.id.should == 5
65
- entity.attributes = { "id" => 8 }
66
- entity.id.should == 8
67
- end
68
-
69
- it "converts typed attributes" do
70
- entity = TestEntity.new
71
- entity.id = "10"
72
- entity.id.should == 10
73
- entity.attributes = { :id => "15" }
74
- entity.id.should == 15
75
- end
76
-
77
- it "can use single line type declarations" do
78
- task = TestTask.new(:due_at => "2012-01-01 15:00")
79
- task.due_at.should == DateTime.parse("2012-01-01 15:00")
80
- end
81
-
82
- it "sets blank values to nil" do
83
- user = TestUser.new
84
- user.name = " "
85
- user.name.should be_nil
86
- end
87
-
88
- it "symbolizes keys" do
89
- entity = TestEntity.new
90
- entity.attributes = { "id" => "15" }
91
- entity.attributes[:id].should == 15
92
- end
93
-
94
- it "inherits attributes" do
95
- user = TestAgedUser.new
96
- user.name = "Name"
97
- user.age = 123
98
- user.name.should == "Name"
99
- user.age.should == 123
100
- end
101
-
102
- it "is possible to override attribute readers with inheritance" do
103
- user = OverridingTestUser.new
104
- user.name = "pelle"
105
- user.name.should == "PELLE"
106
- end
107
-
108
- it "is possible to override attribute writers with inheritance" do
109
- user = OverridingTestUser.new
110
- user.name = " 123 "
111
- user.name.should == "123"
112
- end
113
- end
114
-
115
- describe Minimapper::Entity, "attributes without type" do
116
- it "can be set and get with anything" do
117
- user = TestUser.new
118
- user.name = "Hello"
119
- user.name.should == "Hello"
120
- user.name = 5
121
- user.name.should == 5
122
- end
123
- end
124
-
125
- describe Minimapper::Entity, "attributes" do
126
- it "returns the attributes" do
127
- entity = TestEntity.new(:id => 5)
128
- time = Time.now
129
- entity.created_at = time
130
- entity.attributes.should == { :id => 5, :created_at => time }
131
- end
132
- end
133
-
134
- describe Minimapper::Entity, "self.column_names" do
135
- it "returns all attributes as strings" do
136
- # used by some rails plugins
137
- TestUser.column_names.should == [ "id", "created_at", "updated_at", "name" ]
138
- end
139
-
140
- it "does not leak between different models" do
141
- TestProject.column_names.should == [ "id", "created_at", "updated_at", "title" ]
142
- end
143
33
  end
144
34
 
145
35
  describe Minimapper::Entity, "#==" do
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.7.0
4
+ version: 0.8.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-02 00:00:00.000000000 Z
12
+ date: 2013-06-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70148053526900 !ruby/object:Gem::Requirement
16
+ requirement: &70270060752600 !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: *70148053526900
24
+ version_requirements: *70270060752600
25
25
  description: A minimalistic way of separating your models from ActiveRecord.
26
26
  email:
27
27
  - joakim.kolsjo@gmail.com
@@ -44,6 +44,7 @@ files:
44
44
  - lib/minimapper/entity/convert/to_integer.rb
45
45
  - lib/minimapper/entity/core.rb
46
46
  - lib/minimapper/entity/rails.rb
47
+ - lib/minimapper/entity/validation.rb
47
48
  - lib/minimapper/mapper.rb
48
49
  - lib/minimapper/repository.rb
49
50
  - lib/minimapper/version.rb
@@ -54,9 +55,11 @@ files:
54
55
  - spec/spec_helper.rb
55
56
  - spec/support/database_setup.rb
56
57
  - spec/support/shared_examples/mapper.rb
58
+ - unit/entity/attributes_spec.rb
57
59
  - unit/entity/convert_spec.rb
58
60
  - unit/entity/core_spec.rb
59
61
  - unit/entity/rails_spec.rb
62
+ - unit/entity/validation_spec.rb
60
63
  - unit/entity_spec.rb
61
64
  - unit/repository_spec.rb
62
65
  - unit/spec_helper.rb
@@ -72,18 +75,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
72
75
  - - ! '>='
73
76
  - !ruby/object:Gem::Version
74
77
  version: '0'
75
- segments:
76
- - 0
77
- hash: -4244542897336928819
78
78
  required_rubygems_version: !ruby/object:Gem::Requirement
79
79
  none: false
80
80
  requirements:
81
81
  - - ! '>='
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
- segments:
85
- - 0
86
- hash: -4244542897336928819
87
84
  requirements: []
88
85
  rubyforge_project:
89
86
  rubygems_version: 1.8.5