mince 2.0.0.pre.4 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,7 @@ require_relative 'config'
8
8
  module Mince # :nodoc:
9
9
  # = DataModel
10
10
  #
11
- # Mince::DataModel is used as a mixin to easily mixin behavior into an object that
11
+ # Mince::DataModel is used as a mixin to easily mixin behavior into an object that
12
12
  # you wish to act as a data model and interact with mince data interfaces.
13
13
  #
14
14
  # Simply mixin this module in order to get a wrapper class to interact with a mince
@@ -103,7 +103,7 @@ module Mince # :nodoc:
103
103
 
104
104
  # Increments a field by a given amount
105
105
  #
106
- # Some databases provide very efficient algorithms for incrementing or decrementing a
106
+ # Some databases provide very efficient algorithms for incrementing or decrementing a
107
107
  # value.
108
108
  #
109
109
  # @param [id] id the id of the record to update
@@ -119,7 +119,7 @@ module Mince # :nodoc:
119
119
  # @param [Symbol] field the field to update
120
120
  # @param [*] value the value to update the field with
121
121
  def remove_from_array(id, field, value)
122
- interface.remove_from_array(data_collection, interface.primary_key, id, field, value)
122
+ interface.remove_from_array(data_collection, id, field, value)
123
123
  end
124
124
 
125
125
  # Pushes a value to an array field
@@ -128,7 +128,7 @@ module Mince # :nodoc:
128
128
  # @param [Symbol] field the field to update
129
129
  # @param [*] value the value to update the field with
130
130
  def push_to_array(id, field, value)
131
- interface.push_to_array(data_collection, interface.primary_key, id, field, value)
131
+ interface.push_to_array(data_collection, id, field, value)
132
132
  end
133
133
 
134
134
  # Returns a record that has the given id
@@ -138,7 +138,7 @@ module Mince # :nodoc:
138
138
  # @param [id] id the id of the record to find
139
139
  # @returns [HashWithIndifferentAccess, nil] a hash with the data for the record
140
140
  def find(id)
141
- translate_from_interface interface.find(data_collection, interface.primary_key, id)
141
+ translate_from_interface interface.find(data_collection, id)
142
142
  end
143
143
 
144
144
  # Deletes a field from all records in the collection
@@ -149,7 +149,7 @@ module Mince # :nodoc:
149
149
  end
150
150
 
151
151
 
152
- # Deletes a field from all records that matches the field / value key pairs in the
152
+ # Deletes all records that matches the field / value key pairs in the
153
153
  # params provided in the collection
154
154
  #
155
155
  # This will only delete records that match all key/value pairs in the params hash.
@@ -225,11 +225,23 @@ module Mince # :nodoc:
225
225
  interface.delete_collection(data_collection)
226
226
  end
227
227
 
228
- private
228
+ # Generates a new id to be used for a primary key
229
+ def generate_unique_id(seed)
230
+ interface.generate_unique_id(seed)
231
+ end
232
+
233
+ # Adds a new record with provided data hash
234
+ #
235
+ # @param [Hash] data to add to the data collection
236
+ # @returns [Hash] the data that was added to the data collection, including the uniquely generated id
237
+ def add(hash)
238
+ hash = HashWithIndifferentAccess.new(hash.merge(primary_key => generate_unique_id(hash)))
239
+ interface.add(data_collection, hash).first
240
+ end
229
241
 
230
242
  def translate_from_interface(hash)
231
243
  if hash
232
- hash["id"] = hash[primary_key] if hash[primary_key]
244
+ hash["id"] = hash[primary_key] if hash[primary_key] && (primary_key != :id || primary_key != 'id')
233
245
  HashWithIndifferentAccess.new hash
234
246
  end
235
247
  end
@@ -238,6 +250,8 @@ module Mince # :nodoc:
238
250
  data.collect {|d| translate_from_interface(d) }
239
251
  end
240
252
 
253
+ private
254
+
241
255
  def primary_key
242
256
  @primary_key ||= interface.primary_key
243
257
  end
@@ -293,7 +307,7 @@ module Mince # :nodoc:
293
307
  end
294
308
 
295
309
  def generated_id
296
- interface.generate_unique_id(model)
310
+ self.class.generate_unique_id(model)
297
311
  end
298
312
 
299
313
  def model_has_id?
data/lib/mince/model.rb CHANGED
@@ -1,9 +1,9 @@
1
- require 'active_support'
2
- require 'active_model'
3
- require 'active_support/core_ext/module/delegation'
4
- require 'active_support/core_ext/object/instance_variables'
5
-
6
1
  module Mince
2
+ require_relative 'model/fields'
3
+ require_relative 'model/persistence'
4
+ require_relative 'model/finders'
5
+ require_relative 'model/data_model'
6
+
7
7
  # = Model
8
8
  #
9
9
  # The mince model is a module that provides standard model to data behavior to the Mince data model mixing for a specific model.
@@ -31,131 +31,29 @@ module Mince
31
31
  # book = Book.new title: 'The World In Photographs', publisher: 'National Geographic'
32
32
  # book.save
33
33
  #
34
- # View the docs for each method available
34
+ # By including this module, you are including DataModel, Fields, Persistence, and Finders.
35
+ #
36
+ # However, you can choose which modules you would like by including those modules individually
37
+ # so that you can have flexibility an lighter weight help to implement your models.
38
+ #
39
+ # class AvailableBook
40
+ # include Mince::Model::DataModel
41
+ #
42
+ # data_collection :books
43
+ #
44
+ # def self.all
45
+ # data_collection.all_by_fields(library: "St. Louis - Downtown", available: true).map{ |a| new(a) }
46
+ # end
47
+ # end
48
+ #
35
49
  module Model
36
50
  extend ActiveSupport::Concern
37
51
 
38
52
  included do
39
- include ActiveModel::Conversion
40
- extend ActiveModel::Naming
41
-
42
- attr_accessor :id
43
- end
44
-
45
- module ClassMethods
46
- # Sets or returns the data model class for the model
47
- def data_model(model=nil)
48
- @data_model = model if model
49
- @data_model
50
- end
51
-
52
- # Returns all models from the data model
53
- def all
54
- data_model.all.map{|a| new a }
55
- end
56
-
57
- # Returns a model that matches a given id, returns nil if none found
58
- def find(id)
59
- a = data_model.find(id)
60
- new a if a
61
- end
62
-
63
- # Adds a field to the object. Takes options to indicate assignability. If `assignable`
64
- # is set, the field will be assignable via
65
- # model.field = 'foo'
66
- # model.attributes = { field: 'foo' }
67
- #
68
- def field(field_name, options={})
69
- if options[:assignable]
70
- add_assignable_field(field_name)
71
- else
72
- add_readonly_field(field_name)
73
- end
74
- end
75
-
76
- # Adds a read only field, values for these fields can only be set in the class itself
77
- # or from the hash sent in to the initializer
78
- def add_readonly_field(field_name)
79
- fields << field_name
80
- readonly_fields << field_name
81
- attr_reader field_name
82
- end
83
-
84
- # Adds an assignable field, values for these fields can be set using the field writer
85
- # or from the `attributes=` method.
86
- def add_assignable_field(field_name)
87
- fields << field_name
88
- assignable_fields << field_name
89
- attr_accessor field_name
90
- end
91
-
92
- # Adds multiple readonly fields to the fields array, and returns the current list
93
- # of fields. If no fields are given, it just returns the current list of fields
94
- def fields(*field_names)
95
- @fields ||= []
96
- field_names.each {|field_name| field(field_name) }
97
- @fields
98
- end
99
-
100
- # Returns the list of assignable fields
101
- def assignable_fields
102
- @assignable_fields ||= []
103
- end
104
-
105
- # Returns the list of readonly fields
106
- def readonly_fields
107
- @readonly_fields ||= []
108
- end
109
- end
110
-
111
- delegate :data_model, :assignable_fields, :readonly_fields, :fields, to: 'self.class'
112
-
113
- # Sets values (for fields defined by calling .field or .fields) in the hash to the object
114
- # includes assignable and non-assignable fields
115
- def initialize(hash={})
116
- @id = hash[:id]
117
- readonly_fields.each do |field_name|
118
- self.instance_variable_set("@#{field_name}", hash[field_name]) if hash[field_name]
119
- end
120
- self.attributes = hash
121
- end
122
-
123
- # Returns true if the record indicates that it has been persisted to a data model.
124
- # Returns false otherwise.
125
- def persisted?
126
- !!id
127
- end
128
-
129
- # Saves the object to the data model. Stores if new, updates previous entry if it has already
130
- # been saved.
131
- def save
132
- ensure_no_extra_fields
133
- if persisted?
134
- data_model.update(self)
135
- else
136
- @id = data_model.store(self)
137
- end
138
- end
139
-
140
- # Sets values (for assignable fields only, defined by calling .field or .fields) in the hash
141
- # to the object.
142
- #
143
- # Allows the proxy to have whitelisted attributes to be assigned from http requests.
144
- def attributes=(hash={})
145
- assignable_fields.each do |field|
146
- send("#{field}=", hash[field]) if hash[field]
147
- end
148
- end
149
-
150
- private
151
-
152
- # Ensures that the data model has all of the fields that are trying to be saved. Raises an
153
- # exception if the data model does not.
154
- def ensure_no_extra_fields
155
- extra_fields = (fields - data_model.data_fields)
156
- if extra_fields.any?
157
- raise "Tried to save a #{self.class.name} with fields not specified in #{data_model.name}: #{extra_fields.join(', ')}"
158
- end
53
+ include DataModel
54
+ include Fields
55
+ include Persistence
56
+ include Finders
159
57
  end
160
58
  end
161
59
  end
@@ -0,0 +1,31 @@
1
+ module Mince
2
+ module Model
3
+ require 'active_support'
4
+
5
+ module DataModel
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Sets or returns the data model class for the model
10
+ def data_model(model=nil)
11
+ @data_model = model if model
12
+ @data_model
13
+ end
14
+ end
15
+
16
+ protected
17
+
18
+ # Ensures that the data model has all of the fields that are trying to be saved. Raises an
19
+ # exception if the data model does not.
20
+ #
21
+ # Not sure if this is where this method should live, it requires both
22
+ # Mince::Model::DataModel and Mince::Model::Fields.
23
+ def ensure_no_extra_fields
24
+ extra_fields = (fields - data_model.data_fields)
25
+ if extra_fields.any?
26
+ raise "Tried to save a #{self.class.name} with fields not specified in #{data_model.name}: #{extra_fields.join(', ')}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,89 @@
1
+ module Mince
2
+ module Model
3
+ require 'active_support'
4
+ require 'active_support/core_ext/module/delegation'
5
+ require 'active_support/core_ext/object/instance_variables'
6
+ require_relative 'data_model'
7
+
8
+ module Fields
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include Mince::Model::DataModel
13
+
14
+ attr_accessor :id
15
+ end
16
+
17
+ module ClassMethods
18
+ # Adds a field to the object. Takes options to indicate assignability. If `assignable`
19
+ # is set, the field will be assignable via
20
+ # model.field = 'foo'
21
+ # model.attributes = { field: 'foo' }
22
+ #
23
+ def field(field_name, options={})
24
+ if options[:assignable]
25
+ add_assignable_field(field_name)
26
+ else
27
+ add_readonly_field(field_name)
28
+ end
29
+ end
30
+
31
+ # Adds a read only field, values for these fields can only be set in the class itself
32
+ # or from the hash sent in to the initializer
33
+ def add_readonly_field(field_name)
34
+ fields << field_name
35
+ readonly_fields << field_name
36
+ attr_reader field_name
37
+ end
38
+
39
+ # Adds an assignable field, values for these fields can be set using the field writer
40
+ # or from the `attributes=` method.
41
+ def add_assignable_field(field_name)
42
+ fields << field_name
43
+ assignable_fields << field_name
44
+ attr_accessor field_name
45
+ end
46
+
47
+ # Adds multiple readonly fields to the fields array, and returns the current list
48
+ # of fields. If no fields are given, it just returns the current list of fields
49
+ def fields(*field_names)
50
+ @fields ||= []
51
+ field_names.each {|field_name| field(field_name) }
52
+ @fields
53
+ end
54
+
55
+ # Returns the list of assignable fields
56
+ def assignable_fields
57
+ @assignable_fields ||= []
58
+ end
59
+
60
+ # Returns the list of readonly fields
61
+ def readonly_fields
62
+ @readonly_fields ||= []
63
+ end
64
+ end
65
+
66
+ delegate :assignable_fields, :readonly_fields, :fields, to: 'self.class'
67
+
68
+ # Sets values (for fields defined by calling .field or .fields) in the hash to the object
69
+ # includes assignable and non-assignable fields
70
+ def initialize(hash={})
71
+ @id = hash[:id]
72
+ readonly_fields.each do |field_name|
73
+ self.instance_variable_set("@#{field_name}", hash[field_name]) if hash[field_name]
74
+ end
75
+ self.attributes = hash
76
+ end
77
+
78
+ # Sets values (for assignable fields only, defined by calling .field or .fields) in the hash
79
+ # to the object.
80
+ #
81
+ # Allows the proxy to have whitelisted attributes to be assigned from http requests.
82
+ def attributes=(hash={})
83
+ assignable_fields.each do |field|
84
+ send("#{field}=", hash[field]) if hash[field]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,32 @@
1
+ module Mince
2
+ module Model
3
+ require 'active_support'
4
+ require_relative 'data_model'
5
+
6
+ module Finders
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ include Mince::Model::DataModel
11
+ end
12
+
13
+ module ClassMethods
14
+ # Sets or returns the data model class for the model
15
+ def find_by_fields(*fields)
16
+ raise 'not implemented'
17
+ end
18
+
19
+ # Returns all models from the data model
20
+ def all
21
+ data_model.all.map{|a| new a }
22
+ end
23
+
24
+ # Returns a model that matches a given id, returns nil if none found
25
+ def find(id)
26
+ a = data_model.find(id)
27
+ new a if a
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ module Mince
2
+ module Model
3
+ require 'active_support'
4
+ require 'active_model'
5
+ require 'active_support/core_ext/module/delegation'
6
+ require_relative 'data_model'
7
+
8
+ module Persistence
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include Mince::Model::DataModel
13
+ include ActiveModel::Conversion
14
+ extend ActiveModel::Naming
15
+ end
16
+
17
+ module ClassMethods
18
+ # Creates a record with the given field values
19
+ def create(data)
20
+ new(data).tap(&:save)
21
+ end
22
+ end
23
+
24
+ delegate :data_model, to: 'self.class'
25
+
26
+ # Returns true if the record indicates that it has been persisted to a data model.
27
+ # Returns false otherwise.
28
+ def persisted?
29
+ !!id
30
+ end
31
+
32
+ # Saves the object to the data model. Stores if new, updates previous entry if it has already
33
+ # been saved.
34
+ def save
35
+ ensure_no_extra_fields if self.respond_to?(:ensure_no_extra_fields)
36
+
37
+ if persisted?
38
+ data_model.update(self)
39
+ else
40
+ @id = data_model.store(self)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -103,24 +103,19 @@ shared_examples_for 'a mince interface' do
103
103
  data2[:field_1] = 'value modified'
104
104
  interface.replace(:some_collection, data2)
105
105
 
106
- convert(interface.find(:some_collection, primary_key, 2))[:field_1].should == 'value modified'
106
+ convert(interface.find(:some_collection, 2))[:field_1].should == 'value modified'
107
107
  end
108
108
 
109
109
  it 'can update a field with a value on a specific record' do
110
110
  interface.update_field_with_value(:some_collection, 3, :field_2, '10')
111
111
 
112
- convert(interface.find(:some_collection, primary_key, 3))[:field_2].should == '10'
112
+ convert(interface.find(:some_collection, 3))[:field_2].should == '10'
113
113
  end
114
114
 
115
115
  it 'can increment a field with a given amount for a specific field' do
116
116
  interface.increment_field_by_amount(:some_collection, 1, :field_2, 3)
117
117
 
118
- convert(interface.find(:some_collection, primary_key, 1))[:field_2].should == 6
119
- end
120
-
121
- it 'can get one document' do
122
- convert(interface.find(:some_collection, :field_1, 'value 1')).should == convert(data1)
123
- convert(interface.find(:some_collection, :field_2, 6)).should == convert(data2)
118
+ convert(interface.find(:some_collection, 1))[:field_2].should == 6
124
119
  end
125
120
 
126
121
  it 'can clear the data store' do
@@ -145,18 +140,18 @@ shared_examples_for 'a mince interface' do
145
140
  end
146
141
 
147
142
  it 'can push a value to an array for a specific record' do
148
- interface.push_to_array(:some_collection, primary_key, 1, :field_3, 'add to existing array')
149
- interface.push_to_array(:some_collection, primary_key, 1, :new_field, 'add to new array')
143
+ interface.push_to_array(:some_collection, 1, :field_3, 'add to existing array')
144
+ interface.push_to_array(:some_collection, 1, :new_field, 'add to new array')
150
145
 
151
- record = convert(interface.find(:some_collection, primary_key, 1))
146
+ record = convert(interface.find(:some_collection, 1))
152
147
  record[:field_3].should include('add to existing array')
153
148
  record[:new_field].should == ['add to new array']
154
149
  end
155
150
 
156
151
  it 'can remove a value from an array for a specific record' do
157
- interface.remove_from_array(:some_collection, primary_key, 1, :field_3, 2)
152
+ interface.remove_from_array(:some_collection, 1, :field_3, 2)
158
153
 
159
- convert(interface.find(:some_collection, primary_key, 1))[:field_3].should_not include(2)
154
+ convert(interface.find(:some_collection, 1))[:field_3].should_not include(2)
160
155
  end
161
156
 
162
157
  it 'can get all records that match a given set of keys and values' do
data/lib/mince/version.rb CHANGED
@@ -9,7 +9,7 @@ module Mince
9
9
  end
10
10
 
11
11
  def self.patch
12
- '0.pre.4'
12
+ 1
13
13
  end
14
14
  end
15
15
 
@@ -0,0 +1,42 @@
1
+ require 'mince'
2
+ require 'hashy_db'
3
+
4
+ describe 'A mince data model integration spec' do
5
+ let(:attributes) { { brand: brand, price: price, type: type, color: color } }
6
+ let(:brand) { mock }
7
+ let(:price) { mock }
8
+ let(:type) { mock }
9
+ let(:color) { mock }
10
+ let(:primary_key) { Mince::HashyDb::Interface.primary_key}
11
+
12
+ let(:data_model_klass) do
13
+ Class.new do
14
+ include Mince::DataModel
15
+
16
+ data_collection :guitars
17
+ data_fields :brand, :price, :type, :color
18
+ end
19
+ end
20
+
21
+ before do
22
+ Mince::Config.interface = Mince::HashyDb::Interface
23
+ Mince::HashyDb::Interface.clear
24
+ end
25
+
26
+ after do
27
+ Mince::HashyDb::Interface.clear
28
+ end
29
+
30
+ it 'can insert data directly to the data collection' do
31
+ result = data_model_klass.add attributes
32
+
33
+ all = data_model_klass.all
34
+ all.size.should == 1
35
+ [all.first, result].each do |object|
36
+ %w(brand price type color).each do |field|
37
+ object[field.to_sym].should == attributes[field.to_sym]
38
+ end
39
+ object[primary_key].should_not be_nil
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,106 @@
1
+ require 'mince'
2
+ require 'hashy_db'
3
+
4
+ describe 'A mince model integration spec' do
5
+ subject { model_klass.new attributes }
6
+
7
+ let(:attributes) { { brand: brand, price: price, type: type, color: color } }
8
+ let(:brand) { mock }
9
+ let(:price) { mock }
10
+ let(:type) { mock }
11
+ let(:color) { mock }
12
+
13
+ before do
14
+ Mince::Config.interface = Mince::HashyDb::Interface
15
+ Mince::HashyDb::Interface.clear
16
+ end
17
+
18
+ after do
19
+ Mince::HashyDb::Interface.clear
20
+ end
21
+
22
+ describe 'a model with a limited set of mince model mixins' do
23
+ let(:model_klass) do
24
+ Class.new do
25
+ include Mince::Model::Fields
26
+
27
+ data_model(
28
+ Class.new do
29
+ include Mince::DataModel
30
+
31
+ data_collection :guitars
32
+ data_fields :brand, :price, :type, :color
33
+ end
34
+ )
35
+ fields :brand, :price, :type, :color
36
+ end
37
+ end
38
+
39
+ it 'is initialized with the correct data' do
40
+ subject.brand.should == brand
41
+ subject.price.should == price
42
+ subject.type.should == type
43
+ subject.color.should == color
44
+ end
45
+
46
+ it 'cannot be persisted to the mince data interface' do
47
+ subject.respond_to?(:save).should be_false
48
+ end
49
+ end
50
+
51
+ describe 'a model with all mince model mixins' do
52
+ let(:model_klass) do
53
+ Class.new do
54
+ include Mince::Model
55
+
56
+ data_model(
57
+ Class.new do
58
+ include Mince::DataModel
59
+
60
+ data_collection :guitars
61
+ data_fields :brand, :price, :type, :color
62
+ end
63
+ )
64
+ fields :brand, :price, :type, :color
65
+ end
66
+ end
67
+
68
+ it 'is initialized with the correct data' do
69
+ subject.brand.should == brand
70
+ subject.price.should == price
71
+ subject.type.should == type
72
+ subject.color.should == color
73
+ end
74
+
75
+ it 'can be persisted to the mince data interface' do
76
+ subject.save
77
+
78
+ raw_record = Mince::Config.interface.find(:guitars, subject.id)
79
+ model_record = model_klass.find(subject.id)
80
+ raw_record[:brand].should == brand
81
+ model_record.brand.should == brand
82
+ end
83
+
84
+ context 'when not all fields are defined in the data model' do
85
+ let(:model_klass) do
86
+ Class.new do
87
+ include Mince::Model
88
+
89
+ data_model(
90
+ Class.new do
91
+ include Mince::DataModel
92
+
93
+ data_collection :guitars
94
+ data_fields :brand, :price, :type
95
+ end
96
+ )
97
+ fields :brand, :price, :type, :color
98
+ end
99
+ end
100
+
101
+ it 'raises an exception to provide feedback about the missing field' do
102
+ expect { subject.save }.to raise_exception(RuntimeError, "Tried to save a with fields not specified in : color")
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,16 @@
1
+ shared_examples_for 'a model using mince model data model' do
2
+ before do
3
+ begin
4
+ klass
5
+ rescue NameError
6
+ raise "You must define a `klass` spec variable to use the mince model finders shared example"
7
+ end
8
+ end
9
+
10
+ it 'can set and get the data model' do
11
+ data_model = mock 'data model'
12
+ klass.data_model(data_model)
13
+ klass.data_model.should == data_model
14
+ end
15
+ end
16
+
@@ -0,0 +1,59 @@
1
+ shared_examples_for 'a model using mince model finders' do
2
+ before do
3
+ begin
4
+ klass
5
+ rescue NameError
6
+ raise "You must define a `klass` spec variable to use the mince model finders shared example"
7
+ end
8
+ end
9
+
10
+ describe 'getting all models' do
11
+ subject { klass.all }
12
+
13
+ let(:model) { mock }
14
+ let(:models) { [model] }
15
+ let(:data) { [datum] }
16
+ let(:datum) { mock }
17
+
18
+ before do
19
+ klass.data_model.stub(all: data)
20
+ klass.stub(:new).with(datum).and_return(model)
21
+ end
22
+
23
+ it 'returns an array of all models' do
24
+ subject.should == models
25
+ end
26
+ end
27
+
28
+ describe 'finding a model by id' do
29
+ subject { klass.find(id) }
30
+
31
+ let(:id) { mock 'id' }
32
+
33
+ before do
34
+ klass.data_model.stub(:find).with(id).and_return(data)
35
+ end
36
+
37
+ context 'when it exists' do
38
+ let(:data) { mock 'data' }
39
+ let(:model) { mock 'model' }
40
+
41
+ before do
42
+ klass.stub(:new).with(data).and_return(model)
43
+ end
44
+
45
+ it 'returns the model' do
46
+ subject.should == model
47
+ end
48
+ end
49
+
50
+ context 'when it does not exist' do
51
+ let(:data) { nil }
52
+
53
+ it 'returns nothing' do
54
+ subject.should be_nil
55
+ end
56
+ end
57
+ end
58
+ end
59
+
@@ -31,6 +31,21 @@ describe Mince::DataModel, 'Mixin' do
31
31
  Mince::Config.stub(:interface => interface)
32
32
  end
33
33
 
34
+ describe "inserting data" do
35
+ let(:expected_hash) { data_field_attributes.merge(primary_key => unique_id) }
36
+
37
+ before do
38
+ interface.stub(:add).and_return([expected_hash])
39
+ interface.stub(:generate_unique_id).with(data_field_attributes).and_return(unique_id)
40
+ end
41
+
42
+ it 'adds the data to the db store with the generated id' do
43
+ interface.should_receive(:add).with(collection_name, HashWithIndifferentAccess.new(expected_hash)).and_return([expected_hash])
44
+
45
+ described_class.add(data_field_attributes).should == expected_hash
46
+ end
47
+ end
48
+
34
49
  describe "storing a data model" do
35
50
  let(:model) { mock 'a model', instance_values: data_field_attributes }
36
51
 
@@ -53,7 +68,7 @@ describe Mince::DataModel, 'Mixin' do
53
68
 
54
69
  it 'can delete the collection' do
55
70
  interface.should_receive(:delete_collection).with(collection_name)
56
-
71
+
57
72
  described_class.delete_collection
58
73
  end
59
74
 
@@ -90,7 +105,7 @@ describe Mince::DataModel, 'Mixin' do
90
105
 
91
106
  describe 'updating a specific field for a data model' do
92
107
  let(:data_model_id) { '1234567' }
93
-
108
+
94
109
  it 'has the data store update the field' do
95
110
  interface.should_receive(:update_field_with_value).with(collection_name, data_model_id, :some_field, 'some value')
96
111
 
@@ -112,7 +127,7 @@ describe Mince::DataModel, 'Mixin' do
112
127
  let(:data_model_id) { '1234567' }
113
128
 
114
129
  it 'replaces the data model in the db store' do
115
- interface.should_receive(:push_to_array).with(collection_name, primary_key, data_model_id, :array_field, 'some value')
130
+ interface.should_receive(:push_to_array).with(collection_name, data_model_id, :array_field, 'some value')
116
131
 
117
132
  described_class.push_to_array(data_model_id, :array_field, 'some value')
118
133
  end
@@ -135,7 +150,7 @@ describe Mince::DataModel, 'Mixin' do
135
150
  let(:data_model_id) { '1234567' }
136
151
 
137
152
  it 'removes the value from the array' do
138
- interface.should_receive(:remove_from_array).with(collection_name, primary_key, data_model_id, :array_field, 'some value')
153
+ interface.should_receive(:remove_from_array).with(collection_name, data_model_id, :array_field, 'some value')
139
154
 
140
155
  described_class.remove_from_array(data_model_id, :array_field, 'some value')
141
156
  end
@@ -220,7 +235,7 @@ describe Mince::DataModel, 'Mixin' do
220
235
  let(:data_model) { {primary_key => 'id', :id => 'id' } }
221
236
 
222
237
  it 'returns the data model from the data store' do
223
- interface.should_receive(:find).with(collection_name, primary_key, 'id').and_return(data_model)
238
+ interface.should_receive(:find).with(collection_name, 'id').and_return(data_model)
224
239
 
225
240
  described_class.find(data_model[:id]).should == HashWithIndifferentAccess.new(data_model)
226
241
  end
@@ -0,0 +1,14 @@
1
+ require_relative '../../../../lib/mince/model/data_model'
2
+ require_relative '../../../support/shared_examples/model_data_model_example'
3
+
4
+ describe Mince::Model::DataModel do
5
+ let(:klass) do
6
+ Class.new do
7
+ include Mince::Model::DataModel
8
+
9
+ data_model Class.new
10
+ end
11
+ end
12
+
13
+ it_behaves_like 'a model using mince model data model'
14
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../../../lib/mince/model/finders'
2
+ require_relative '../../../support/shared_examples/model_finders_example'
3
+
4
+ describe Mince::Model::Finders do
5
+ let(:klass) do
6
+ Class.new do
7
+ include Mince::Model::Finders
8
+
9
+ data_model Class.new
10
+ end
11
+ end
12
+
13
+ it_behaves_like 'a model using mince model finders'
14
+ end
@@ -94,6 +94,15 @@ describe Mince::Model do
94
94
  end
95
95
 
96
96
  describe "Query Methods:" do
97
+ it 'provides a way to easily create a new record' do
98
+ model = mock 'model'
99
+ data = mock 'data'
100
+ klass.stub(:new).with(data).and_return(model)
101
+ model.should_receive(:save)
102
+
103
+ klass.create(data)
104
+ end
105
+
97
106
  describe 'finding a model by id' do
98
107
  subject { klass.find(id) }
99
108
 
@@ -126,3 +135,4 @@ describe Mince::Model do
126
135
  end
127
136
  end
128
137
  end
138
+
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mince
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.4
5
- prerelease: 6
4
+ version: 2.0.1
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Matt Simpson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-11-02 00:00:00.000000000 Z
13
+ date: 2013-02-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -145,17 +145,17 @@ dependencies:
145
145
  requirement: !ruby/object:Gem::Requirement
146
146
  none: false
147
147
  requirements:
148
- - - '='
148
+ - - ~>
149
149
  - !ruby/object:Gem::Version
150
- version: 2.0.0.pre
150
+ version: '2.0'
151
151
  type: :development
152
152
  prerelease: false
153
153
  version_requirements: !ruby/object:Gem::Requirement
154
154
  none: false
155
155
  requirements:
156
- - - '='
156
+ - - ~>
157
157
  - !ruby/object:Gem::Version
158
- version: 2.0.0.pre
158
+ version: '2.0'
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rb-fsevent
161
161
  requirement: !ruby/object:Gem::Requirement
@@ -180,16 +180,25 @@ extensions: []
180
180
  extra_rdoc_files: []
181
181
  files:
182
182
  - lib/mince.rb
183
- - lib/mince/version.rb
184
183
  - lib/mince/config.rb
185
184
  - lib/mince/data_model.rb
186
185
  - lib/mince/model.rb
186
+ - lib/mince/version.rb
187
187
  - lib/mince/shared_examples/interface_example.rb
188
+ - lib/mince/model/data_model.rb
189
+ - lib/mince/model/fields.rb
190
+ - lib/mince/model/finders.rb
191
+ - lib/mince/model/persistence.rb
192
+ - spec/integration/mince_data_model_spec.rb
193
+ - spec/integration/mince_model_spec.rb
194
+ - spec/support/shared_examples/modeL_data_model_example.rb
195
+ - spec/support/shared_examples/model_finders_example.rb
196
+ - spec/units/mince/model/data_model_spec.rb
197
+ - spec/units/mince/model/finders_spec.rb
188
198
  - spec/units/mince/config_spec.rb
189
199
  - spec/units/mince/interface_example_spec.rb
190
200
  - spec/units/mince/data_model_spec.rb
191
201
  - spec/units/mince/model_spec.rb
192
- - spec/integration/simple_mince_data_model_spec.rb
193
202
  homepage: https://github.com/coffeencoke/mince
194
203
  licenses: []
195
204
  post_install_message:
@@ -205,19 +214,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
214
  required_rubygems_version: !ruby/object:Gem::Requirement
206
215
  none: false
207
216
  requirements:
208
- - - ! '>'
217
+ - - ! '>='
209
218
  - !ruby/object:Gem::Version
210
- version: 1.3.1
219
+ version: '0'
211
220
  requirements: []
212
221
  rubyforge_project: mince
213
- rubygems_version: 1.8.24
222
+ rubygems_version: 1.8.25
214
223
  signing_key:
215
224
  specification_version: 3
216
225
  summary: Library to interact with mince interfacing data libraries
217
226
  test_files:
227
+ - spec/integration/mince_data_model_spec.rb
228
+ - spec/integration/mince_model_spec.rb
229
+ - spec/support/shared_examples/modeL_data_model_example.rb
230
+ - spec/support/shared_examples/model_finders_example.rb
231
+ - spec/units/mince/model/data_model_spec.rb
232
+ - spec/units/mince/model/finders_spec.rb
218
233
  - spec/units/mince/config_spec.rb
219
234
  - spec/units/mince/interface_example_spec.rb
220
235
  - spec/units/mince/data_model_spec.rb
221
236
  - spec/units/mince/model_spec.rb
222
- - spec/integration/simple_mince_data_model_spec.rb
223
237
  has_rdoc: true
@@ -1,55 +0,0 @@
1
- require 'mince'
2
- require 'hashy_db'
3
-
4
- describe 'A simple mince data model integration spec' do
5
- before do
6
- Mince::Config.interface = Mince::HashyDb::Interface
7
- Mince::HashyDb::Interface.clear
8
- end
9
-
10
- after do
11
- Mince::HashyDb::Interface.clear
12
- end
13
-
14
- describe 'a model' do
15
- subject { model_klass.new attributes }
16
-
17
- let(:model_klass) do
18
- Class.new do
19
- include Mince::Model
20
-
21
- data_model(
22
- Class.new do
23
- include Mince::DataModel
24
-
25
- data_collection :guitars
26
- data_fields :brand, :price, :type, :color
27
- end
28
- )
29
- fields :brand, :price, :type, :color
30
- end
31
- end
32
-
33
- let(:attributes) { { brand: brand, price: price, type: type, color: color } }
34
- let(:brand) { mock }
35
- let(:price) { mock }
36
- let(:type) { mock }
37
- let(:color) { mock }
38
-
39
- it 'is initialized with the correct data' do
40
- subject.brand.should == brand
41
- subject.price.should == price
42
- subject.type.should == type
43
- subject.color.should == color
44
- end
45
-
46
- it 'can be persisted to the mince data interface' do
47
- subject.save
48
-
49
- raw_record = Mince::Config.interface.find(:guitars, Mince::HashyDb::Interface.primary_key, subject.id)
50
- model_record = model_klass.find(subject.id)
51
- raw_record[:brand].should == brand
52
- model_record.brand.should == brand
53
- end
54
- end
55
- end