mince_model 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: