id 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -I .
@@ -0,0 +1 @@
1
+ ree-1.8.7-2012.02
data/Gemfile CHANGED
@@ -2,3 +2,4 @@ source 'https://rubygems.org'
2
2
  gemspec
3
3
  gem 'test-unit'
4
4
  gem 'json', '~> 1.7.7'
5
+ gem 'money', '3.7.1'
@@ -20,10 +20,10 @@ GEM
20
20
  diff-lcs (1.2.1)
21
21
  i18n (0.6.4)
22
22
  json (1.7.7)
23
- money (5.1.1)
24
- i18n (~> 0.6.0)
23
+ money (3.7.1)
24
+ i18n (~> 0.4)
25
25
  multi_json (1.7.3)
26
- optional (0.0.6)
26
+ optional (0.0.7)
27
27
  rspec (2.13.0)
28
28
  rspec-core (~> 2.13.0)
29
29
  rspec-expectations (~> 2.13.0)
@@ -44,6 +44,7 @@ PLATFORMS
44
44
  DEPENDENCIES
45
45
  id!
46
46
  json (~> 1.7.7)
47
+ money (= 3.7.1)
47
48
  rspec
48
49
  simplecov
49
50
  test-unit
data/README.md CHANGED
@@ -58,3 +58,8 @@ Types are inferred from the association name unless one is specified.
58
58
  You can even set fields on nested models in this way:
59
59
 
60
60
  person.hat.set(color: 'red') # => returns a new person object with a new hat object with its color set to red
61
+
62
+ #### Avoiding nils
63
+
64
+ `id` tries to avoid nils entirely, by using the Option pattern found in many functional programming languages and implemented [here](http://github.com/rsslldnphy/optional).
65
+ Just mark optional fields as `optional: true` and their accessors will return either `Some[value]` or `None`.
data/id.gemspec CHANGED
@@ -1,11 +1,11 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'id'
3
- s.version = '0.0.9'
3
+ s.version = '0.0.10'
4
4
  s.date = '2013-03-28'
5
5
  s.summary = "Simple models based on hashes"
6
6
  s.description = "Developed at On The Beach Ltd. Contact russell.dunphy@onthebeach.co.uk"
7
7
  s.authors = ["Russell Dunphy", "Radek Molenda"]
8
- s.email = ['russell@russelldunphy.com', 'radek.molenda@gmail.com']
8
+ s.email = ['rssll@rsslldnphy.com', 'radek.molenda@gmail.com']
9
9
  s.files = `git ls-files`.split($\)
10
10
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
11
11
  s.require_paths = ["lib"]
data/lib/id.rb CHANGED
@@ -4,4 +4,19 @@ require 'active_support/core_ext/string/inflections'
4
4
  require 'active_support/core_ext/hash/except'
5
5
  require 'optional'
6
6
  require 'money'
7
- require_relative 'id/all'
7
+ require 'id/missing_attribute_error'
8
+ require 'id/hashifier'
9
+ require 'id/model/definer'
10
+ require 'id/model/descriptor'
11
+ require 'id/model/type_casts'
12
+ require 'id/model/field'
13
+ require 'id/model/association'
14
+ require 'id/model/has_one'
15
+ require 'id/model/has_many'
16
+ require 'id/model'
17
+ require 'id/timestamps'
18
+ require 'id/form'
19
+ require 'id/form/active_model_form'
20
+ require 'id/form/descriptor'
21
+ require 'id/form/field_with_form_support'
22
+ require 'id/form/field_form'
@@ -0,0 +1,21 @@
1
+ module Id
2
+ module Form
3
+
4
+ def as_form
5
+ @form_object ||= self.class.form_object.new(self)
6
+ end
7
+
8
+ def errors
9
+ as_form.errors
10
+ end
11
+
12
+ def valid?
13
+ as_form.valid?
14
+ end
15
+
16
+ def self.included(base)
17
+ base.extend(Descriptor)
18
+ end
19
+
20
+ end
21
+ end
@@ -1,6 +1,6 @@
1
1
  module Id
2
- module Model
3
- class Form
2
+ module Form
3
+ class ActiveModelForm
4
4
  include ActiveModel::Validations
5
5
  include ActiveModel::Conversion
6
6
  extend ActiveModel::Naming
@@ -0,0 +1,27 @@
1
+ module Id
2
+ module Form
3
+ module Descriptor
4
+
5
+ def field(f, options={})
6
+ FieldWithFormSupport.new(self, f, options).define
7
+ end
8
+
9
+ def form &block
10
+ form_object.send :instance_exec, &block
11
+ end
12
+
13
+ def form_object
14
+ base = self
15
+ @form_object ||= Class.new(ActiveModelForm) do
16
+ eingenclass = class << self
17
+ self
18
+ end
19
+ eingenclass.send(:define_method, :model_name) do
20
+ ActiveModel::Name.new(self, nil, base.name)
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ class FieldForm
2
+
3
+ def self.define(field)
4
+ field.model.form_object.instance_eval do
5
+ define_method field.name do
6
+ memoize field.name do
7
+ Option[model.send(field.name)].flatten.value_or nil if model.data.has_key? field.key
8
+ end
9
+ end
10
+ attr_writer field.name
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,12 @@
1
+ module Id
2
+ module Form
3
+ class FieldWithFormSupport < Id::Model::Field
4
+
5
+ def hook_define
6
+ FieldForm.define(self)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
12
+
@@ -23,18 +23,6 @@ module Id
23
23
  data.hash
24
24
  end
25
25
 
26
- def as_form
27
- @form_object ||= self.class.form_object.new(self)
28
- end
29
-
30
- def errors
31
- as_form.errors
32
- end
33
-
34
- def valid?
35
- as_form.valid?
36
- end
37
-
38
26
  private
39
27
 
40
28
  def self.included(base)
@@ -42,7 +30,7 @@ module Id
42
30
  end
43
31
 
44
32
  def memoize(f, &b)
45
- instance_variable_get("@#{f}") || instance_variable_set("@#{f}", b.call)
33
+ instance_variable_get("@#{f}") || instance_variable_set("@#{f}", b.call(data))
46
34
  end
47
35
 
48
36
  end
@@ -26,7 +26,9 @@ module Id
26
26
  end
27
27
 
28
28
  def parent
29
- @parent ||= constants.find { |c| c.const_defined? child }
29
+ @parent ||= constants.find do |c|
30
+ c.ancestors.find { |anc| anc.const_defined? child }
31
+ end
30
32
  end
31
33
 
32
34
  def constants
@@ -0,0 +1,23 @@
1
+ module Id
2
+ module Model
3
+ class Definer
4
+
5
+ def self.method_memoize(context, name, &value_block)
6
+ method(context, name) do |object|
7
+ object.instance_eval do
8
+ memoize(name, &value_block)
9
+ end
10
+ end
11
+ end
12
+
13
+ def self.method(context, name, &value_block)
14
+ context.instance_eval do
15
+ define_method name do
16
+ value_block.call(self)
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -3,48 +3,19 @@ module Id
3
3
  module Descriptor
4
4
 
5
5
  def field(f, options={})
6
- (options[:optional] ? FieldOption : Field).new(self, f, options).define
6
+ Field.new(self, f, options).define
7
7
  end
8
8
 
9
9
  def has_one(f, options={})
10
- (options[:optional] ? HasOneOption : HasOne).new(self, f, options).define
10
+ HasOne.new(self, f, options).define
11
11
  end
12
12
 
13
13
  def has_many(f, options={})
14
14
  HasMany.new(self, f, options).define
15
15
  end
16
16
 
17
- def compound_field(f, fields, options={})
18
- CompoundField.new(self, f, fields, options).define
19
- end
20
-
21
- def builder
22
- builder_class.new(self)
23
- end
24
-
25
- def form &block
26
- form_object.send :instance_exec, &block
27
- end
28
-
29
- def form_object
30
- base = self
31
- @form_object ||= Class.new(Form) do
32
- instance_exec do
33
- define_singleton_method :model_name do
34
- ActiveModel::Name.new(self, nil, base.name)
35
- end
36
- end
37
- end
38
- end
39
-
40
17
  def to_proc
41
- ->(data) { new data }
42
- end
43
-
44
- private
45
-
46
- def builder_class
47
- @builder_class ||= Class.new { include Builder }
18
+ lambda { |data| new data }
48
19
  end
49
20
 
50
21
  end
@@ -8,41 +8,22 @@ module Id
8
8
  @options = options
9
9
  end
10
10
 
11
- def define_form_field
12
- field = self
13
- model.form_object.send :define_method, name do
14
- memoize field.name do
15
- Option[model.send(field.name)].flatten.value_or nil if model.data.has_key? field.key
16
- end
17
- end
18
- model.form_object.send :attr_writer, name
19
- end
20
-
21
- def define_getter
22
- field = self
23
- model.send :define_method, name do
24
- memoize field.name do
25
- field.cast data.fetch(field.key, &field.default_value)
26
- end
27
- end
11
+ def define
12
+ Definer.method_memoize(model, name) { |data| value_of(data) }
13
+ Definer.method(model, "#{name}?") { |obj| presence_of(obj.data) }
14
+ hook_define
28
15
  end
29
16
 
30
- def define_setter
31
- model.send(:builder_class).define_setter name
17
+ def hook_define
32
18
  end
33
19
 
34
- def define_is_present
35
- field = self
36
- model.send :define_method, "#{name}?" do
37
- data.has_key?(field.key) && !data.fetch(field.key).nil?
38
- end
20
+ def value_of(data)
21
+ value = data.fetch(key, &default_value)
22
+ optional ? Option[value].map{ |d| cast d } : cast(value)
39
23
  end
40
24
 
41
- def define
42
- define_getter
43
- define_setter
44
- define_is_present
45
- define_form_field
25
+ def presence_of(data)
26
+ data.has_key?(key) && !data.fetch(key).nil?
46
27
  end
47
28
 
48
29
  def cast(value)
@@ -71,21 +52,10 @@ module Id
71
52
  def optional?
72
53
  options.fetch(:optional, false)
73
54
  end
55
+ alias_method :optional, :optional?
74
56
 
75
57
  attr_reader :model, :name, :options
76
- end
77
58
 
78
- class FieldOption < Field
79
- def define_getter
80
- field = self
81
- model.send :define_method, name do
82
- memoize field.name do
83
- Option[data.fetch(field.key, &field.default_value)].map do |d|
84
- field.cast d
85
- end
86
- end
87
- end
88
- end
89
59
  end
90
60
  end
91
61
  end
@@ -2,13 +2,8 @@ module Id
2
2
  module Model
3
3
  class HasMany < Association
4
4
 
5
- def define_getter
6
- field = self
7
- model.send :define_method, name do
8
- memoize field.name do
9
- data.fetch(field.key, []).map { |r| field.type.new(r) }
10
- end
11
- end
5
+ def value_of(data)
6
+ data.fetch(key, []).map { |r| type.new(r) }
12
7
  end
13
8
 
14
9
  end
@@ -2,27 +2,13 @@ module Id
2
2
  module Model
3
3
  class HasOne < Association
4
4
 
5
- def define_getter
6
- field = self
7
- model.send :define_method, name do
8
- memoize field.name do
9
- child = data.fetch(field.key) { raise MissingAttributeError, field.key }
10
- field.type.new(child) unless child.nil?
11
- end
12
- end
13
- end
14
-
15
- end
16
-
17
- class HasOneOption < Association
18
-
19
- def define_getter
20
- field = self
21
- model.send :define_method, name do
22
- memoize field.name do
23
- child = data.fetch(field.key, nil)
24
- child.nil? ? None : Some[field.type.new(child)]
25
- end
5
+ def value_of(data)
6
+ if optional?
7
+ child = data.fetch(field.key, nil)
8
+ child.nil? ? None : Some[field.type.new(child)]
9
+ else
10
+ child = data.fetch(key) { raise MissingAttributeError, key }
11
+ type.new(child) unless child.nil?
26
12
  end
27
13
  end
28
14
 
@@ -1,23 +1,20 @@
1
1
  module Id
2
2
  module Timestamps
3
-
4
3
  def self.included(base)
5
4
  base.field :created_at
6
5
  base.field :updated_at
7
6
  end
8
7
 
9
8
  def initialize(data = {})
10
- super data.merge(_timestamps data)
9
+ super data.merge(:created_at => data.fetch('created_at', Time.now))
11
10
  end
12
11
 
13
- private
14
-
15
- def _timestamps(data, now=Time.now)
16
- {
17
- created_at: data.fetch('created_at', now),
18
- updated_at: now
19
- }
12
+ def set(values)
13
+ self.class.new(super.data.merge(:updated_at => Time.now))
20
14
  end
21
15
 
16
+ def unset(*keys)
17
+ self.class.new(super.data.merge(:updated_at => Time.now))
18
+ end
22
19
  end
23
20
  end
@@ -11,7 +11,7 @@ describe Id::Model::Association do
11
11
  end
12
12
  end
13
13
 
14
- let (:model) { stub(name: "Foo::Bar::Baz::Quux") }
14
+ let (:model) { stub(:name => "Foo::Bar::Baz::Quux") }
15
15
  let (:has_one) { Id::Model::Association.new(model, "yak", {}) }
16
16
 
17
17
  describe "hierarchy" do
@@ -2,13 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  class Gerbil
4
4
  include Id::Model
5
+ include Id::Form
5
6
 
6
7
  field :name
7
8
  field :paws
8
9
 
9
10
  form do
10
11
  validates_presence_of :name
11
- validates_length_of :name, maximum: 4
12
+ validates_length_of :name, :maximum => 4
12
13
  end
13
14
 
14
15
  def name_in_caps
@@ -21,7 +22,7 @@ module Id
21
22
  module Model
22
23
  describe Form do
23
24
 
24
- let (:gerbil) { Gerbil.new(name: 'Berty') }
25
+ let (:gerbil) { Gerbil.new(:name => 'Berty') }
25
26
  let (:form) { gerbil.as_form }
26
27
 
27
28
  subject { gerbil.as_form }
@@ -5,28 +5,20 @@ class NestedModel
5
5
  field :yak
6
6
  end
7
7
 
8
- class CompboundElementModel
9
- include Id::Model
10
- field :plugh
11
- field :thud
12
- end
13
-
14
8
  class TestModel
15
9
  include Id::Model
16
10
 
17
11
  field :foo
18
- field :bar, key: 'baz'
19
- field :qux, optional: true
20
- field :quux, default: false
21
- field :date_of_birth, optional: true, type: Date
22
- field :empty_date, optional: true, type: Date
23
- field :christmas, default: Date.new(2014,12,25), type: Date
24
- field :quxx, optional: true
25
-
26
- compound_field :corge, {plugh: 'foo', thud: 'quux'}, type: CompboundElementModel
27
-
28
- has_one :aliased_model, type: NestedModel
29
- has_one :nested_model, key: 'aliased_model'
12
+ field :bar, :key => 'baz'
13
+ field :qux, :optional => true
14
+ field :quux, :default => false
15
+ field :date_of_birth, :optional => true, :type => Date
16
+ field :empty_date, :optional => true, :type => Date
17
+ field :christmas, :default => Date.new(2014,12,25), :type => Date
18
+ field :quxx, :optional => true
19
+
20
+ has_one :aliased_model, :type => NestedModel
21
+ has_one :nested_model, :key => 'aliased_model'
30
22
  has_one :extra_nested_model
31
23
  has_one :test_model
32
24
  has_many :nested_models
@@ -38,19 +30,19 @@ class TestModel
38
30
  end
39
31
 
40
32
  describe Id::Model do
41
- let (:model) { TestModel.new(foo: 3,
42
- baz: 6,
43
- quxx: 8,
44
- test_model: {},
45
- date_of_birth: '06-06-1983',
46
- aliased_model: { 'yak' => 11},
47
- nested_models: [{ 'yak' => 11}, { yak: 14 }],
48
- extra_nested_model: { cats: "MIAOW" }) }
33
+ let (:model) { TestModel.new(:foo => 3,
34
+ :baz => 6,
35
+ :quxx => 8,
36
+ :test_model => {},
37
+ :date_of_birth => '06-06-1983',
38
+ :aliased_model => { 'yak' => 11},
39
+ :nested_models => [{ 'yak' => 11}, { :yak => 14 }],
40
+ :extra_nested_model => { :cats => "MIAOW" }) }
49
41
 
50
42
 
51
43
  describe ".new" do
52
44
  it 'converts any passed id models to their hash representations' do
53
- new_model = TestModel.new(test_model: model)
45
+ new_model = TestModel.new(:test_model => model)
54
46
  new_model.test_model.data.should eq model.data
55
47
  end
56
48
  end
@@ -96,16 +88,6 @@ describe Id::Model do
96
88
 
97
89
  end
98
90
 
99
- describe ".compound_field" do
100
- it 'defines an accessor on the model' do
101
- model.corge.should be_a CompboundElementModel
102
- end
103
-
104
- it 'deals with default values' do
105
- model.corge.thud.should be_false
106
- end
107
- end
108
-
109
91
  describe ".has_one" do
110
92
  it "allows nested models" do
111
93
  model.aliased_model.should be_a NestedModel
@@ -134,14 +116,14 @@ describe Id::Model do
134
116
 
135
117
  describe "#set" do
136
118
  it "creates a new model with the provided values changed" do
137
- model.set(foo: 999).should be_a TestModel
138
- model.set(foo: 999).foo.should eq 999
119
+ model.set(:foo => 999).should be_a TestModel
120
+ model.set(:foo => 999).foo.should eq 999
139
121
  end
140
122
  end
141
123
 
142
124
  describe "#unset" do
143
125
  it 'returns a new basket minus the passed key' do
144
- expect { model.set(foo: 999, bar: 555).unset(:foo, :bar).foo }.to raise_error Id::MissingAttributeError, "foo"
126
+ expect { model.set(:foo => 999, :bar => 555).unset(:foo, :bar).foo }.to raise_error Id::MissingAttributeError, "foo"
145
127
  end
146
128
 
147
129
  it 'does not error if the key to be removed does not exist' do
@@ -151,7 +133,7 @@ describe Id::Model do
151
133
 
152
134
  describe "#fields are present methods" do
153
135
  it 'allows you to check if fields are present' do
154
- model = TestModel.new(foo: 1)
136
+ model = TestModel.new(:foo => 1)
155
137
  model.foo?.should be_true
156
138
  model.bar?.should be_false
157
139
  end
@@ -159,38 +141,38 @@ describe Id::Model do
159
141
 
160
142
  describe "#==" do
161
143
  it 'is equal to another id model with the same data' do
162
- one = TestModel.new(foo: 1)
163
- two = TestModel.new(foo: 1)
144
+ one = TestModel.new(:foo => 1)
145
+ two = TestModel.new(:foo => 1)
164
146
  one.should eq two
165
147
  end
166
148
 
167
149
  it 'is not equal to two models with different data' do
168
- one = TestModel.new(foo: 1)
169
- two = TestModel.new(foo: 2)
150
+ one = TestModel.new(:foo => 1)
151
+ two = TestModel.new(:foo => 2)
170
152
  one.should_not eq two
171
153
  end
172
154
  end
173
155
 
174
156
  describe "#hash" do
175
157
  it 'allows id models to be used as hash keys' do
176
- one = TestModel.new(foo: 1)
177
- two = TestModel.new(foo: 1)
158
+ one = TestModel.new(:foo => 1)
159
+ two = TestModel.new(:foo => 1)
178
160
  hash = { one => :found }
179
161
  hash[two].should eq :found
180
162
  end
181
163
  it 'they are different keys if the data is different' do
182
- one = TestModel.new(foo: 1)
183
- two = TestModel.new(foo: 2)
164
+ one = TestModel.new(:foo => 1)
165
+ two = TestModel.new(:foo => 2)
184
166
  hash = { one => :found }
185
167
  hash[two].should be_nil
186
168
  hash[one].should eq :found
187
169
  end
188
170
  end
189
171
 
190
- describe ".to_proc" do
191
- it 'allows eta expansion of the class name to its constructor' do
192
- [{foo: 1}].map(&TestModel).first.should be_a TestModel
193
- [{foo: 1}].map(&TestModel).first.foo.should eq 1
172
+ describe "#to_proc" do
173
+ it 'eta expands the model class into its constructor' do
174
+ [{},{}].map(&TestModel).all? { |m| m.is_a? TestModel }.should be_true
194
175
  end
195
176
  end
177
+
196
178
  end
@@ -11,18 +11,14 @@ end
11
11
  module Id
12
12
  describe Timestamps do
13
13
 
14
- let (:model) { TimeStampedModel.new(foo: 999, bar: 666) }
14
+ let(:model) { TimeStampedModel.new(:foo => 999, :bar => 666) }
15
15
 
16
16
  it 'should have a created_at date' do
17
17
  model.created_at.should be_a Time
18
18
  end
19
19
 
20
- it 'should have an updated_at date' do
21
- model.updated_at.should be_a Time
22
- end
23
-
24
20
  it 'should update the updated at when set is called' do
25
- updated = model.set(foo: 123)
21
+ updated = model.set(:foo => 123)
26
22
  expect(updated.created_at).to be < updated.updated_at
27
23
  end
28
24
 
@@ -4,7 +4,7 @@ class Mike
4
4
  include Id::Model
5
5
 
6
6
  field :cat
7
- field :dog, optional: true
7
+ field :dog, :optional => true
8
8
 
9
9
  def catdog
10
10
  dog.value_or cat
@@ -13,7 +13,7 @@ class Mike
13
13
  end
14
14
 
15
15
  describe "Foobar" do
16
- let (:mike) { Mike.new(cat: 'pooface') }
16
+ let (:mike) { Mike.new(:cat => 'pooface') }
17
17
  it 'returns cat' do
18
18
  mike.catdog.should eq 'pooface'
19
19
  end
@@ -1,11 +1,6 @@
1
- require 'simplecov'
2
- SimpleCov.start do
3
- add_filter '/spec'
4
- end
5
-
6
1
  require 'rspec'
7
- require_relative '../lib/id'
8
- require_relative 'support/active_model_lint'
2
+ require 'lib/id'
3
+ require 'support/active_model_lint'
9
4
 
10
5
 
11
6
  RSpec.configure do |config|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -110,39 +110,40 @@ dependencies:
110
110
  version: '0'
111
111
  description: Developed at On The Beach Ltd. Contact russell.dunphy@onthebeach.co.uk
112
112
  email:
113
- - russell@russelldunphy.com
113
+ - rssll@rsslldnphy.com
114
114
  - radek.molenda@gmail.com
115
115
  executables: []
116
116
  extensions: []
117
117
  extra_rdoc_files: []
118
118
  files:
119
119
  - .gitignore
120
+ - .rspec
121
+ - .ruby-version
120
122
  - Gemfile
121
123
  - Gemfile.lock
122
124
  - LICENSE.md
123
125
  - README.md
124
126
  - id.gemspec
125
127
  - lib/id.rb
126
- - lib/id/all.rb
128
+ - lib/id/form.rb
129
+ - lib/id/form/active_model_form.rb
130
+ - lib/id/form/descriptor.rb
131
+ - lib/id/form/field_form.rb
132
+ - lib/id/form/field_with_form_support.rb
127
133
  - lib/id/hashifier.rb
128
134
  - lib/id/missing_attribute_error.rb
129
135
  - lib/id/model.rb
130
- - lib/id/model/all.rb
131
136
  - lib/id/model/association.rb
132
- - lib/id/model/builder.rb
133
- - lib/id/model/compound_field.rb
137
+ - lib/id/model/definer.rb
134
138
  - lib/id/model/descriptor.rb
135
139
  - lib/id/model/field.rb
136
- - lib/id/model/form.rb
137
140
  - lib/id/model/has_many.rb
138
141
  - lib/id/model/has_one.rb
139
142
  - lib/id/model/type_casts.rb
140
143
  - lib/id/timestamps.rb
141
144
  - spec/lib/id/model/association_spec.rb
142
- - spec/lib/id/model/builder_spec.rb
143
145
  - spec/lib/id/model/field_spec.rb
144
146
  - spec/lib/id/model/form_spec.rb
145
- - spec/lib/id/model/has_one_spec.rb
146
147
  - spec/lib/id/model/type_casts_spec.rb
147
148
  - spec/lib/id/model_spec.rb
148
149
  - spec/lib/id/timestamps_spec.rb
@@ -175,10 +176,8 @@ specification_version: 3
175
176
  summary: Simple models based on hashes
176
177
  test_files:
177
178
  - spec/lib/id/model/association_spec.rb
178
- - spec/lib/id/model/builder_spec.rb
179
179
  - spec/lib/id/model/field_spec.rb
180
180
  - spec/lib/id/model/form_spec.rb
181
- - spec/lib/id/model/has_one_spec.rb
182
181
  - spec/lib/id/model/type_casts_spec.rb
183
182
  - spec/lib/id/model_spec.rb
184
183
  - spec/lib/id/timestamps_spec.rb
@@ -1,5 +0,0 @@
1
- require_relative 'missing_attribute_error'
2
- require_relative 'hashifier'
3
- require_relative 'model/all'
4
- require_relative 'model'
5
- require_relative 'timestamps'
@@ -1,9 +0,0 @@
1
- require_relative 'descriptor'
2
- require_relative 'type_casts'
3
- require_relative 'field'
4
- require_relative 'association'
5
- require_relative 'has_one'
6
- require_relative 'has_many'
7
- require_relative 'builder'
8
- require_relative 'compound_field'
9
- require_relative 'form'
@@ -1,45 +0,0 @@
1
- module Id
2
- module Model
3
- module Builder
4
-
5
- def initialize(model, data={})
6
- @model = model
7
- @data = data
8
- end
9
-
10
- def build
11
- model.new data
12
- end
13
-
14
- private
15
-
16
- def set(f, value)
17
- self.class.new(model, data.merge(f.to_s => ensure_hash(value)))
18
- end
19
-
20
- def ensure_hash(value)
21
- case value
22
- when Id::Model then value.data
23
- when Array then value.map { |v| ensure_hash(v) }
24
- else value end
25
- end
26
-
27
- attr_reader :model, :data
28
-
29
- def self.included(base)
30
- base.extend(FieldBuilder)
31
- end
32
-
33
- module FieldBuilder
34
-
35
- def define_setter(f)
36
- define_method f do |value|
37
- set(f, value)
38
- end
39
- end
40
-
41
- end
42
-
43
- end
44
- end
45
- end
@@ -1,23 +0,0 @@
1
- module Id
2
- module Model
3
- class CompoundField < Association
4
-
5
- def initialize(model, name, fields, options)
6
- @fields = fields
7
- super(model, name, options)
8
- end
9
-
10
- def define_getter
11
- field = self
12
- model.send :define_method, name do
13
- memoize field.name do
14
- compound = Hash[field.fields.map { |k,v| [k.to_s, send(v) { raise MissingAttributeError, k.to_s }]}]
15
- field.type.new(compound)
16
- end
17
- end
18
- end
19
-
20
- attr_accessor :fields
21
- end
22
- end
23
- end
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class BuilderModel
4
- include Id::Model
5
-
6
- field :foo
7
- field :bar
8
- has_one :nested_builder_model
9
- has_many :nested_builder_models
10
-
11
- class NestedBuilderModel
12
- include Id::Model
13
-
14
- field :baz
15
- end
16
-
17
- end
18
-
19
- module Id
20
- describe Model::Builder do
21
-
22
- it 'models can be built using a builder' do
23
- BuilderModel.builder.build.should be_a BuilderModel
24
- end
25
-
26
- it 'defines chainable setter methods for each field' do
27
- model = BuilderModel.builder.foo(4).bar("hello cat").build
28
- model.foo.should eq 4
29
- model.bar.should eq "hello cat"
30
- end
31
-
32
- it 'allows setting of has_one associations using their respective builders' do
33
- nested_model = BuilderModel::NestedBuilderModel.builder.baz(:quux).build
34
- model = BuilderModel.builder.nested_builder_model(nested_model).build
35
- model.nested_builder_model.baz.should eq :quux
36
- end
37
-
38
- it 'allows setting of has_many associations using their respective builders' do
39
- nested_model = BuilderModel::NestedBuilderModel.builder.baz(:quux).build
40
- model = BuilderModel.builder.nested_builder_models([nested_model]).build
41
- model.nested_builder_models.first.baz.should eq :quux
42
- end
43
-
44
- end
45
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class Cat
4
- include Id::Model
5
- end
6
-
7
- class OptionalModel
8
- include Id::Model
9
-
10
- has_one :cat, optional: true
11
- end
12
-
13
- module Id
14
- module Model
15
-
16
- describe HasOneOption do
17
-
18
- it 'returns a none if the key is missing' do
19
- OptionalModel.new({}).cat.should be_none
20
- end
21
-
22
- it 'returns a some if the key is there' do
23
- OptionalModel.new(cat: {}).cat.should be_some(Cat)
24
- end
25
-
26
- end
27
-
28
- end
29
- end