plain_old_model 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,17 +4,19 @@ module PlainOldModel
4
4
  module AttributeAssignment
5
5
  module ClassMethods
6
6
  def has_one(attr_name, options={})
7
- if options[:class_name]
8
- associations[attr_name] = options[:class_name].to_s.capitalize unless options[:class_name].nil?
9
- else
10
- associations[attr_name] = attr_name.to_s.capitalize
11
- end
12
- attr_accessor attr_name
7
+ associations << HasOneAssociation.new(attr_name, options)
8
+ attr_accessor attr_name
9
+ end
10
+
11
+ def has_many(attr_name, options={})
12
+ associations << HasManyAssociation.new(attr_name, options)
13
+ attr_accessor attr_name
13
14
  end
14
15
 
15
16
  def associations
16
- @associations ||= {}
17
+ @associations ||= []
17
18
  end
19
+
18
20
  end
19
21
 
20
22
  def self.included(klass)
@@ -23,21 +25,65 @@ module PlainOldModel
23
25
 
24
26
  def assign_attributes(new_attributes, options = {})
25
27
  return unless new_attributes
26
- associations.each do |k, v|
27
- if new_attributes.include?(k)
28
- new_klass = k.to_s.camelcase.constantize.new(new_attributes[k])
28
+ associations.each do |association|
29
+ attr_name = association.attr_name
30
+ if new_attributes.include?(attr_name)
31
+ value = association.create_value_from_attributes(new_attributes[attr_name])
29
32
 
30
- respond_to?("#{k}=") ? (send("#{k}=", new_klass)) : (instance_variable_set("@#{k}".to_sym, new_klass))
31
- new_attributes = new_attributes.delete_if { |key, value| key == k }
33
+ set_attribute(attr_name, value)
34
+ new_attributes = new_attributes.delete_if { |key, value| key.to_s == attr_name.to_s }
32
35
  end
33
36
  end
34
- assignment(new_attributes, options)
37
+ assign_simple_attributes(new_attributes, options)
35
38
  end
36
39
 
37
40
  def associations
38
41
  self.class.associations
39
42
  end
40
43
 
44
+ class Association
45
+ attr_reader :attr_name
46
+
47
+ def initialize(attr_name, options)
48
+ @attr_name = attr_name
49
+ @options = options
50
+ end
51
+
52
+ def create_value_from_attributes(attributes)
53
+ if @options[:factory_method]
54
+ klass.send(@options[:factory_method], attributes)
55
+ else
56
+ klass.new(attributes)
57
+ end
58
+ end
59
+
60
+ def klass
61
+ if @options[:class_name]
62
+ @options[:class_name].to_s.camelcase.constantize
63
+ else
64
+ klass_from_attr_name
65
+ end
66
+ end
67
+
68
+ def klass_from_attr_name
69
+ @attr_name.to_s.camelcase.constantize
70
+ end
71
+ end
72
+
73
+ class HasOneAssociation < Association
74
+
75
+ end
76
+
77
+ class HasManyAssociation < Association
78
+ def create_value_from_attributes(items)
79
+ items.map{|item| super(item)}
80
+ end
81
+
82
+ def klass_from_attr_name
83
+ @attr_name.to_s.singularize.camelcase.constantize
84
+ end
85
+ end
86
+
41
87
  private
42
88
  def sanitize_attributes(attributes)
43
89
  sanitized_attributes = {}
@@ -49,17 +95,19 @@ module PlainOldModel
49
95
  sanitized_attributes
50
96
  end
51
97
 
52
- def assignment(attributes, options)
98
+ def assign_simple_attributes(attributes, options)
53
99
  attributes = sanitize_attributes(attributes).stringify_keys
54
100
 
55
101
  attributes.each do |k, v|
56
- if respond_to?("#{k}=")
57
- send("#{k}=", v)
58
- elsif respond_to?("#{k}")
59
- instance_variable_set("@#{k}".to_sym, v)
60
- else
61
- raise(Exception)
62
- end
102
+ set_attribute(k, v)
103
+ end
104
+ end
105
+
106
+ def set_attribute(attr_name, value)
107
+ if respond_to?("#{attr_name}=")
108
+ send("#{attr_name}=", value)
109
+ else
110
+ instance_variable_set("@#{attr_name}".to_sym, value)
63
111
  end
64
112
  end
65
113
  end
@@ -12,7 +12,7 @@ module PlainOldModel
12
12
  include ActiveModel::Conversion
13
13
  include PlainOldModel::AttributeAssignment
14
14
 
15
- def initialize(attributes = nil, options = {})
15
+ def initialize(attributes = {}, options = {})
16
16
  assign_attributes(attributes, options) if attributes
17
17
  end
18
18
 
@@ -1,3 +1,3 @@
1
1
  module PlainOldModel
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -37,45 +37,76 @@ describe PlainOldModel::Base do
37
37
  end
38
38
 
39
39
  describe "associations" do
40
- it "should return empty hash for unassociated class" do
41
- @person = Person.new()
42
- @person.associations.should == {}
40
+ it "should return empty array for unassociated class" do
41
+ @person = Continent.new
42
+ @person.associations.should == []
43
43
  end
44
44
  it "should provide all the associations when the class has associations" do
45
- @address = Address.new()
46
- @address.associations.should == {:country => "Country"}
47
- end
48
- it "should create a new instance and assign_attributes to the associated class" do
49
- @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India"}, :read_test => 'This should not be assigned',:write_test => "this shd be available"})
50
- @address.country.class.should == Country
51
- end
52
- it "should create the nested class instance and assign_attributes to the associated nested class" do
53
- @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India", :continent => {:name => "asia"}}, :read_test => 'This should not be assigned',:write_test => "this shd be available"})
54
- @address.country.continent.class.should == Continent
45
+ @address = Address.new
46
+ @address.associations.length.should == 1
47
+ @address.associations.first.attr_name.should == :country
55
48
  end
56
- it "should create a new instance and assign_attributes to the associated class" do
57
- @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India", :continent => {:name => "asia", :desc => {:this => "is a test", :actual_desc => "is another test"}}}, :read_test => 'This should not be assigned',:write_test => "this shd be available"})
58
- @address.country.continent.class.should == Continent
59
- @address.country.continent.name.should == "asia"
60
- @continent = @address.country.continent
61
- @continent.name.should == "asia"
49
+ describe "has_one" do
50
+ it "should create a new instance and assign_attributes to the associated class" do
51
+ @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India"}, :read_test => 'This should not be assigned',:write_test => "this shd be available"})
52
+ @address.country.class.should == Country
53
+ end
54
+ it "should create the nested class instance and assign_attributes to the associated nested class" do
55
+ @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India", :continent => {:name => "asia"}}, :read_test => 'This should not be assigned',:write_test => "this shd be available"})
56
+ @address.country.continent.class.should == Continent
57
+ end
58
+ it "should create a new instance and assign_attributes to the associated class" do
59
+ @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India", :continent => {:name => "asia", :desc => {:this => "is a test", :actual_desc => "is another test"}}}, :read_test => 'This should not be assigned',:write_test => "this shd be available"})
60
+ @address.country.continent.class.should == Continent
61
+ @address.country.continent.name.should == "asia"
62
+ @continent = @address.country.continent
63
+ @continent.name.should == "asia"
64
+ end
65
+ it "should assign values to the read only attributes" do
66
+ @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India"}, :read_test => 'This should be assigned',:write_test => "this shd be available"})
67
+ @address.read_test.should == "This should be assigned"
68
+ end
62
69
  end
63
- it "should assign values to the read only attributes" do
64
- @address = Address.new({:fname => "first value", :lname => "second value", :country => {:code => "In", :name => "India"}, :read_test => 'This should be assigned',:write_test => "this shd be available"})
65
- @address.read_test.should == "This should be assigned"
70
+ describe "has_many" do
71
+ it "should create a new instance and assign attributes for each value in array" do
72
+ @person = Person.new({ addresses: [{ fname: "first name 1", lname: "last name 1"}, { fname: "first name 2", lname: "last name 2"}]})
73
+ @person.addresses.length.should == 2
74
+ @person.addresses.first.class.should == Address
75
+ @person.addresses.first.fname.should == "first name 1"
76
+ @person.addresses.first.lname.should == "last name 1"
77
+ @person.addresses[1].class.should == Address
78
+ @person.addresses[1].fname.should == "first name 2"
79
+ @person.addresses[1].lname.should == "last name 2"
80
+ end
81
+
82
+ it "should create each class via factory_method if one is specified" do
83
+ @person = Person.new({ phones: [{ number: '423-5841'}, {number: '383-9139'}]})
84
+ @person.phones.length.should == 2
85
+ @person.phones[0].number.should == '423-5841'
86
+ @person.phones[0].extension.should == 'set_via_factory'
87
+ @person.phones[1].extension.should == 'set_via_factory'
88
+ end
66
89
  end
67
90
  end
68
-
69
-
70
91
  end
71
92
 
72
93
 
73
94
  class Person < PlainOldModel::Base
74
95
  attr_accessor :fname, :lname, :address
75
- #has_one :address
96
+ has_many :addresses
97
+ has_many :phones, factory_method: :create
76
98
  validates_presence_of :fname
77
99
  end
78
100
 
101
+ class Phone < PlainOldModel::Base
102
+ attr_accessor :number, :extension
103
+
104
+ def self.create(attributes)
105
+ attributes[:extension] = 'set_via_factory'
106
+ new(attributes)
107
+ end
108
+ end
109
+
79
110
  class Address < PlainOldModel::Base
80
111
  attr_accessor :fname, :lname
81
112
  attr_reader :read_test
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plain_old_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-11 00:00:00.000000000 Z
13
+ date: 2013-02-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
- requirement: &70282593825980 !ruby/object:Gem::Requirement
17
+ requirement: &70107737128780 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70282593825980
25
+ version_requirements: *70107737128780
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
28
- requirement: &70282593825520 !ruby/object:Gem::Requirement
28
+ requirement: &70107737128360 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *70282593825520
36
+ version_requirements: *70107737128360
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: rake
39
- requirement: &70282593825100 !ruby/object:Gem::Requirement
39
+ requirement: &70107737127940 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *70282593825100
47
+ version_requirements: *70107737127940
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: rspec
50
- requirement: &70282593824660 !ruby/object:Gem::Requirement
50
+ requirement: &70107737127440 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: '0'
56
56
  type: :development
57
57
  prerelease: false
58
- version_requirements: *70282593824660
58
+ version_requirements: *70107737127440
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: rspec-core
61
- requirement: &70282593824180 !ruby/object:Gem::Requirement
61
+ requirement: &70107737126940 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: '0'
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *70282593824180
69
+ version_requirements: *70107737126940
70
70
  description: ! "This gem is created to cater the projects which do not require a backend/database,\n
71
71
  \ but still need some of the niceties offered by the ActiveRecord"
72
72
  email: