plain_old_model 0.1.0 → 0.1.2
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.
- data/lib/plain_old_model/attribute_assignment.rb +69 -21
- data/lib/plain_old_model/base.rb +1 -1
- data/lib/plain_old_model/version.rb +1 -1
- data/spec/lib/base_spec.rb +56 -25
- metadata +12 -12
@@ -4,17 +4,19 @@ module PlainOldModel
|
|
4
4
|
module AttributeAssignment
|
5
5
|
module ClassMethods
|
6
6
|
def has_one(attr_name, options={})
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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 |
|
27
|
-
|
28
|
-
|
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
|
-
|
31
|
-
new_attributes
|
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
|
-
|
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
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
data/lib/plain_old_model/base.rb
CHANGED
@@ -12,7 +12,7 @@ module PlainOldModel
|
|
12
12
|
include ActiveModel::Conversion
|
13
13
|
include PlainOldModel::AttributeAssignment
|
14
14
|
|
15
|
-
def initialize(attributes =
|
15
|
+
def initialize(attributes = {}, options = {})
|
16
16
|
assign_attributes(attributes, options) if attributes
|
17
17
|
end
|
18
18
|
|
data/spec/lib/base_spec.rb
CHANGED
@@ -37,45 +37,76 @@ describe PlainOldModel::Base do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
describe "associations" do
|
40
|
-
it "should return empty
|
41
|
-
@person =
|
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 ==
|
47
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
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.
|
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-
|
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: &
|
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: *
|
25
|
+
version_requirements: *70107737128780
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: activemodel
|
28
|
-
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: *
|
36
|
+
version_requirements: *70107737128360
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: rake
|
39
|
-
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: *
|
47
|
+
version_requirements: *70107737127940
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rspec
|
50
|
-
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: *
|
58
|
+
version_requirements: *70107737127440
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: rspec-core
|
61
|
-
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: *
|
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:
|