mince_model 0.1.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.
@@ -0,0 +1,103 @@
1
+ require 'active_support'
2
+ require 'active_model'
3
+ require 'active_support/core_ext/module/delegation'
4
+
5
+ require "mince_model/version"
6
+
7
+
8
+ module MinceModel
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include ActiveModel::Conversion
13
+ extend ActiveModel::Naming
14
+
15
+ attr_accessor :id
16
+ end
17
+
18
+ module ClassMethods
19
+ def data_model(model=nil)
20
+ @data_model = model if model
21
+ @data_model
22
+ end
23
+
24
+ def all
25
+ data_model.all.map{|a| new a }
26
+ end
27
+
28
+ def find(id)
29
+ a = data_model.find(id)
30
+ new a if a
31
+ end
32
+
33
+ def field(field_name, options={})
34
+ if options[:assignable]
35
+ add_assignable_field(field_name)
36
+ else
37
+ add_readonly_field(field_name)
38
+ end
39
+ end
40
+
41
+ def add_readonly_field(field_name)
42
+ fields << field_name
43
+ readonly_fields << field_name
44
+ attr_reader field_name
45
+ end
46
+
47
+ def add_assignable_field(field_name)
48
+ fields << field_name
49
+ assignable_fields << field_name
50
+ attr_accessor field_name
51
+ end
52
+
53
+ def fields(*field_names)
54
+ @fields ||= []
55
+ field_names.each {|field_name| field(field_name) }
56
+ @fields
57
+ end
58
+
59
+ def assignable_fields
60
+ @assignable_fields ||= []
61
+ end
62
+
63
+ def readonly_fields
64
+ @readonly_fields ||= []
65
+ end
66
+ end
67
+
68
+ delegate :data_model, :assignable_fields, :readonly_fields, :fields, to: 'self.class'
69
+
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
+ def persisted?
79
+ !!id
80
+ end
81
+
82
+ def save
83
+ ensure_no_extra_fields
84
+ if persisted?
85
+ data_model.update(self)
86
+ else
87
+ @id = data_model.store(self)
88
+ end
89
+ end
90
+
91
+ def ensure_no_extra_fields
92
+ extra_fields = (fields - data_model.data_fields)
93
+ if extra_fields.any?
94
+ raise "Tried to save a #{self.class.name} with fields not specified in #{data_model.name}: #{extra_fields.join(', ')}"
95
+ end
96
+ end
97
+
98
+ def attributes=(hash={})
99
+ assignable_fields.each do |field|
100
+ send("#{field}=", hash[field]) if hash[field]
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module MinceModel
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,128 @@
1
+ require_relative '../../lib/mince_model'
2
+
3
+ describe MinceModel do
4
+ let(:klass) do
5
+ Class.new do
6
+ include MinceModel
7
+
8
+ data_model Class.new
9
+
10
+ field :meh
11
+ field :foo, assignable: true
12
+ field :bar, assignable: false
13
+ fields :baz, :qaaz
14
+ end
15
+ end
16
+
17
+ let(:meh) { mock 'meh' }
18
+ let(:foo) { mock 'foo' }
19
+ let(:bar) { mock 'bar' }
20
+ let(:baz) { mock 'baz' }
21
+ let(:qaaz) { mock 'qaaz' }
22
+
23
+ subject { klass.new(meh: meh, foo: foo, bar: bar, baz: baz, qaaz: qaaz) }
24
+
25
+ it 'initializes the object and assigns values to the fields' do
26
+ subject.meh.should == meh
27
+ subject.foo.should == foo
28
+ subject.bar.should == bar
29
+ subject.baz.should == baz
30
+ subject.qaaz.should == qaaz
31
+ end
32
+
33
+ it 'can set the assignable fields outside of the initilizer' do
34
+ subject.foo = 'foo1'
35
+ subject.foo.should == 'foo1'
36
+ subject.attributes = { foo: 'foo2' }
37
+ subject.foo.should == 'foo2'
38
+ end
39
+
40
+ it 'cannot set the readonly field outside of the initilizer' do
41
+ subject.attributes = { bar: 'bar1' }
42
+ subject.bar.should == bar
43
+ end
44
+
45
+ it 'fields are readonly by default' do
46
+ subject.attributes = { meh: 'meh1' }
47
+ subject.meh.should == meh
48
+ end
49
+
50
+ describe 'saving' do
51
+ let(:id) { mock 'id' }
52
+ let(:data_fields) { subject.fields }
53
+
54
+ before do
55
+ subject.data_model.stub(:data_fields).and_return(data_fields)
56
+ end
57
+
58
+ context 'when the model has fields that are not defined in the data model' do
59
+ let(:data_fields) { subject.fields - extra_fields }
60
+ let(:extra_fields) { subject.fields[0..-2] }
61
+
62
+ it 'raises an exception with a message' do
63
+ expect { subject.save }.to raise_error("Tried to save a #{subject.class.name} with fields not specified in #{subject.data_model.name}: #{extra_fields.join(', ')}")
64
+ end
65
+ end
66
+
67
+ context 'when it has not yet been persisted to the mince data model' do
68
+ before do
69
+ subject.data_model.stub(:store => id)
70
+ end
71
+
72
+ it 'stores the model' do
73
+ subject.data_model.should_receive(:store).with(subject).and_return(id)
74
+
75
+ subject.save
76
+ end
77
+
78
+ it 'assigns the id' do
79
+ subject.save
80
+
81
+ subject.id.should == id
82
+ end
83
+ end
84
+
85
+ context 'when it has already been persisted to the mince data model' do
86
+ let(:subject) { klass.new(id: id) }
87
+
88
+ it 'updates the model' do
89
+ subject.data_model.should_receive(:update).with(subject)
90
+
91
+ subject.save
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "Query Methods:" do
97
+ describe 'finding a model by id' do
98
+ subject { klass.find(id) }
99
+
100
+ let(:id) { mock 'id' }
101
+
102
+ before do
103
+ klass.data_model.stub(:find).with(id).and_return(data)
104
+ end
105
+
106
+ context 'when it exists' do
107
+ let(:data) { mock 'data' }
108
+ let(:model) { mock 'model' }
109
+
110
+ before do
111
+ klass.stub(:new).with(data).and_return(model)
112
+ end
113
+
114
+ it 'returns the model' do
115
+ subject.should == model
116
+ end
117
+ end
118
+
119
+ context 'when it does not exist' do
120
+ let(:data) { nil }
121
+
122
+ it 'returns nothing' do
123
+ subject.should be_nil
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mince_model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Simpson
9
+ - Craig Buchek
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-08-20 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '3.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '3.2'
31
+ - !ruby/object:Gem::Dependency
32
+ name: activemodel
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '3.2'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '3.2'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.11'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '2.11'
63
+ description: Common model behavior for objects backed by Mince
64
+ email:
65
+ - matt.simpson3@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - lib/mince_model.rb
71
+ - lib/mince_model/version.rb
72
+ - spec/lib/mince_model_spec.rb
73
+ homepage: http://github.com/ionicmobile/mince_model
74
+ licenses: []
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 1.8.24
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: Common model behavior for objects backed by Mince
97
+ test_files:
98
+ - spec/lib/mince_model_spec.rb
99
+ has_rdoc: