property 0.6.0 → 0.7.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.
- data/History.txt +6 -0
- data/lib/property.rb +2 -1
- data/lib/property/attribute.rb +1 -1
- data/lib/property/column.rb +18 -2
- data/lib/property/core_ext/time.rb +19 -0
- data/lib/property/declaration.rb +88 -58
- data/lib/property/properties.rb +17 -9
- data/property.gemspec +2 -1
- data/test/unit/property/attribute_test.rb +92 -2
- data/test/unit/property/declaration_test.rb +21 -0
- data/test/unit/property/validation_test.rb +28 -2
- metadata +2 -1
data/History.txt
CHANGED
data/lib/property.rb
CHANGED
|
@@ -4,9 +4,10 @@ require 'property/properties'
|
|
|
4
4
|
require 'property/column'
|
|
5
5
|
require 'property/declaration'
|
|
6
6
|
require 'property/serialization/json'
|
|
7
|
+
require 'property/core_ext/time'
|
|
7
8
|
|
|
8
9
|
module Property
|
|
9
|
-
VERSION = '0.
|
|
10
|
+
VERSION = '0.7.0'
|
|
10
11
|
|
|
11
12
|
def self.included(base)
|
|
12
13
|
base.class_eval do
|
data/lib/property/attribute.rb
CHANGED
|
@@ -50,7 +50,7 @@ module Property
|
|
|
50
50
|
|
|
51
51
|
private
|
|
52
52
|
def attributes_with_properties=(attributes, guard_protected_attributes = true)
|
|
53
|
-
property_columns = self.
|
|
53
|
+
property_columns = self.properties.columns
|
|
54
54
|
properties = {}
|
|
55
55
|
|
|
56
56
|
attributes.keys.each do |k|
|
data/lib/property/column.rb
CHANGED
|
@@ -26,8 +26,24 @@ module Property
|
|
|
26
26
|
@indexed
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def
|
|
30
|
-
|
|
29
|
+
def default_for(owner)
|
|
30
|
+
if default.kind_of?(Proc)
|
|
31
|
+
default.call
|
|
32
|
+
elsif default.kind_of?(Symbol)
|
|
33
|
+
owner.send(default)
|
|
34
|
+
else
|
|
35
|
+
default
|
|
36
|
+
end
|
|
31
37
|
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
def extract_property_options(options)
|
|
41
|
+
@indexed = options.delete(:indexed)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def extract_default(default)
|
|
45
|
+
(default.kind_of?(Proc) || default.kind_of?(Symbol)) ? default : type_cast(default)
|
|
46
|
+
end
|
|
47
|
+
|
|
32
48
|
end # Column
|
|
33
49
|
end # Property
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# We provide our own 'to_json' version because the default is just an alias for 'to_s' and we
|
|
2
|
+
# do not get the correct type back.
|
|
3
|
+
#
|
|
4
|
+
# In order to keep speed up, we have done some compromizes: all time values are considered to
|
|
5
|
+
# be UTC: we do not encode the timezone. We also ignore micro seconds.
|
|
6
|
+
class Time
|
|
7
|
+
JSON_REGEXP = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)\z/
|
|
8
|
+
JSON_FORMAT = "%Y-%m-%d %H:%M:%S"
|
|
9
|
+
|
|
10
|
+
def self.json_create(serialized)
|
|
11
|
+
if serialized['data'] =~ JSON_REGEXP
|
|
12
|
+
Time.utc $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_json(*args)
|
|
17
|
+
{ 'json_class' => self.class.name, 'data' => strftime(JSON_FORMAT) }.to_json(*args)
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/property/declaration.rb
CHANGED
|
@@ -18,66 +18,84 @@ module Property
|
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
class DefinitionProxy
|
|
22
|
+
def initialize(klass)
|
|
23
|
+
@klass = klass
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def column(name, default, type, options)
|
|
27
|
+
if columns[name.to_s]
|
|
28
|
+
raise TypeError.new("Property '#{name}' is already defined.")
|
|
29
|
+
else
|
|
30
|
+
add_column(Property::Column.new(name, default, type, options))
|
|
25
31
|
end
|
|
32
|
+
end
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
def add_column(column)
|
|
35
|
+
own_columns[column.name] = column
|
|
36
|
+
@klass.define_property_methods(column) if column.should_create_accessors?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# If someday we find the need to insert other native classes directly in the DB, we
|
|
40
|
+
# could use this:
|
|
41
|
+
# p.serialize MyClass, xxx, xxx
|
|
42
|
+
# def serialize(klass, name, options={})
|
|
43
|
+
# if @klass.super_property_columns[name.to_s]
|
|
44
|
+
# raise TypeError.new("Property '#{name}' is already defined in a superclass.")
|
|
45
|
+
# elsif !@klass.validate_property_class(type)
|
|
46
|
+
# raise TypeError.new("Custom type '#{type}' cannot be serialized.")
|
|
47
|
+
# else
|
|
48
|
+
# # Find a way to insert the type (maybe with 'serialize'...)
|
|
49
|
+
# # (@klass.own_property_columns ||= {})[name] = Property::Column.new(name, type, options)
|
|
50
|
+
# end
|
|
51
|
+
# end
|
|
52
|
+
|
|
53
|
+
# def string(*args)
|
|
54
|
+
# options = args.extract_options!
|
|
55
|
+
# column_names = args
|
|
56
|
+
# default = options.delete(:default)
|
|
57
|
+
# column_names.each { |name| column(name, default, 'string', options) }
|
|
58
|
+
# end
|
|
59
|
+
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
|
60
|
+
class_eval <<-EOV
|
|
61
|
+
def #{column_type}(*args)
|
|
62
|
+
options = args.extract_options!
|
|
63
|
+
column_names = args
|
|
64
|
+
default = options.delete(:default)
|
|
65
|
+
column_names.each { |name| column(name, default, '#{column_type}', options) }
|
|
34
66
|
end
|
|
67
|
+
EOV
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
def own_columns
|
|
72
|
+
@klass.own_property_columns ||= {}
|
|
35
73
|
end
|
|
36
74
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# p.serialize MyClass, xxx, xxx
|
|
40
|
-
# def serialize(klass, name, options={})
|
|
41
|
-
# if @klass.super_property_columns[name.to_s]
|
|
42
|
-
# raise TypeError.new("Property '#{name}' is already defined in a superclass.")
|
|
43
|
-
# elsif !@klass.validate_property_class(type)
|
|
44
|
-
# raise TypeError.new("Custom type '#{type}' cannot be serialized.")
|
|
45
|
-
# else
|
|
46
|
-
# # Find a way to insert the type (maybe with 'serialize'...)
|
|
47
|
-
# # (@klass.own_property_columns ||= {})[name] = Property::Column.new(name, type, options)
|
|
48
|
-
# end
|
|
49
|
-
# end
|
|
50
|
-
|
|
51
|
-
# def string(*args)
|
|
52
|
-
# options = args.extract_options!
|
|
53
|
-
# column_names = args
|
|
54
|
-
# default = options.delete(:default)
|
|
55
|
-
# column_names.each { |name| column(name, default, 'string', options) }
|
|
56
|
-
# end
|
|
57
|
-
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
|
58
|
-
class_eval <<-EOV
|
|
59
|
-
def #{column_type}(*args)
|
|
60
|
-
options = args.extract_options!
|
|
61
|
-
column_names = args
|
|
62
|
-
default = options.delete(:default)
|
|
63
|
-
column_names.each { |name| column(name, default, '#{column_type}', options) }
|
|
64
|
-
end
|
|
65
|
-
EOV
|
|
75
|
+
def columns
|
|
76
|
+
@klass.property_columns
|
|
66
77
|
end
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
def own_columns
|
|
70
|
-
@klass.own_property_columns ||= {}
|
|
71
|
-
end
|
|
79
|
+
end
|
|
72
80
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
class InstanceDefinitionProxy < DefinitionProxy
|
|
82
|
+
def initialize(instance)
|
|
83
|
+
@properties = instance.prop
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def add_column(column)
|
|
87
|
+
columns[column.name] = column
|
|
88
|
+
end
|
|
76
89
|
|
|
90
|
+
def columns
|
|
91
|
+
@properties.columns
|
|
77
92
|
end
|
|
93
|
+
end
|
|
78
94
|
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
module ClassMethods
|
|
96
|
+
|
|
97
|
+
# Use this class method to declare properties that will be used in your models.
|
|
98
|
+
# Example:
|
|
81
99
|
# property.string 'phone', :default => ''
|
|
82
100
|
#
|
|
83
101
|
# You can also use a block:
|
|
@@ -92,6 +110,10 @@ module Property
|
|
|
92
110
|
proxy
|
|
93
111
|
end
|
|
94
112
|
|
|
113
|
+
# @internal.
|
|
114
|
+
# If you need the list of columns (including instance columns), you should use
|
|
115
|
+
# properties.columns
|
|
116
|
+
#
|
|
95
117
|
# Return the list of all properties defined for the current class, including the properties
|
|
96
118
|
# defined in the parent class.
|
|
97
119
|
def property_columns
|
|
@@ -180,20 +202,28 @@ module Property
|
|
|
180
202
|
|
|
181
203
|
# Evaluate the definition for an attribute related method
|
|
182
204
|
def evaluate_attribute_property_method(attr_name, method_definition, method_name=attr_name)
|
|
183
|
-
|
|
184
|
-
class_eval(method_definition, __FILE__, __LINE__)
|
|
185
|
-
rescue SyntaxError => err
|
|
186
|
-
if logger
|
|
187
|
-
logger.warn "Exception occurred during method compilation."
|
|
188
|
-
logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
|
|
189
|
-
logger.warn err.message
|
|
190
|
-
end
|
|
191
|
-
end
|
|
205
|
+
class_eval(method_definition, __FILE__, __LINE__)
|
|
192
206
|
end
|
|
193
207
|
end # ClassMethods
|
|
194
208
|
|
|
195
209
|
module InstanceMethods
|
|
196
210
|
|
|
211
|
+
# Use this method to declare properties *for the current* instance.
|
|
212
|
+
# Example:
|
|
213
|
+
# @obj.property.string 'phone', :default => ''
|
|
214
|
+
#
|
|
215
|
+
# You can also use a block:
|
|
216
|
+
# @obj.property do |p|
|
|
217
|
+
# p.string 'phone', 'name', :default => ''
|
|
218
|
+
# end
|
|
219
|
+
def property
|
|
220
|
+
proxy = @instance_definition_proxy ||= InstanceDefinitionProxy.new(self)
|
|
221
|
+
if block_given?
|
|
222
|
+
yield proxy
|
|
223
|
+
end
|
|
224
|
+
proxy
|
|
225
|
+
end
|
|
226
|
+
|
|
197
227
|
protected
|
|
198
228
|
def properties_validation
|
|
199
229
|
properties.validate
|
data/lib/property/properties.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Property
|
|
|
14
14
|
def []=(key, value)
|
|
15
15
|
if column = columns[key]
|
|
16
16
|
if value.blank?
|
|
17
|
-
if default = column.
|
|
17
|
+
if default = column.default_for(@owner)
|
|
18
18
|
super(key, default)
|
|
19
19
|
else
|
|
20
20
|
delete(key)
|
|
@@ -36,8 +36,7 @@ module Property
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def validate
|
|
39
|
-
|
|
40
|
-
column_names = @owner.class.property_column_names
|
|
39
|
+
column_names = columns.keys
|
|
41
40
|
errors = @owner.errors
|
|
42
41
|
no_errors = true
|
|
43
42
|
|
|
@@ -52,20 +51,29 @@ module Property
|
|
|
52
51
|
missing_keys.each do |key|
|
|
53
52
|
column = columns[key]
|
|
54
53
|
if column.has_default?
|
|
55
|
-
self[key] = column.
|
|
54
|
+
self[key] = column.default_for(@owner)
|
|
56
55
|
end
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
keys_to_validate.each do |key|
|
|
60
|
-
|
|
59
|
+
value = self[key]
|
|
60
|
+
column = columns[key]
|
|
61
|
+
if value.blank?
|
|
62
|
+
if column.has_default?
|
|
63
|
+
self[key] = column.default_for(@owner)
|
|
64
|
+
else
|
|
65
|
+
delete(key)
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
columns[key].validate(self[key], errors)
|
|
69
|
+
end
|
|
61
70
|
end
|
|
62
71
|
|
|
63
72
|
bad_keys.empty?
|
|
64
73
|
end
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
end
|
|
75
|
+
def columns
|
|
76
|
+
@columns ||= @owner.class.property_columns
|
|
77
|
+
end
|
|
70
78
|
end
|
|
71
79
|
end
|
data/property.gemspec
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{property}
|
|
8
|
-
s.version = "0.
|
|
8
|
+
s.version = "0.7.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Renaud Kern", "Gaspard Bucher"]
|
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
"lib/property.rb",
|
|
26
26
|
"lib/property/attribute.rb",
|
|
27
27
|
"lib/property/column.rb",
|
|
28
|
+
"lib/property/core_ext/time.rb",
|
|
28
29
|
"lib/property/declaration.rb",
|
|
29
30
|
"lib/property/dirty.rb",
|
|
30
31
|
"lib/property/properties.rb",
|
|
@@ -97,11 +97,11 @@ class AttributeTest < Test::Unit::TestCase
|
|
|
97
97
|
subject { Version.new }
|
|
98
98
|
|
|
99
99
|
setup do
|
|
100
|
-
subject.properties={'foo'=>'bar'
|
|
100
|
+
subject.properties={'foo'=>'bar'}
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
should 'be accessible with :properties method' do
|
|
104
|
-
assert_equal Hash['foo'=>'bar'
|
|
104
|
+
assert_equal Hash['foo'=>'bar'], subject.properties
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
should 'be accessible with native methods' do
|
|
@@ -127,6 +127,96 @@ class AttributeTest < Test::Unit::TestCase
|
|
|
127
127
|
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
context 'Retrieving' do
|
|
131
|
+
context 'a saved string' do
|
|
132
|
+
subject do
|
|
133
|
+
klass = Class.new(ActiveRecord::Base) do
|
|
134
|
+
include Property
|
|
135
|
+
set_table_name :dummies
|
|
136
|
+
property.string 'mystring'
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
obj = klass.create('mystring' => 'some data')
|
|
140
|
+
klass.find(obj)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
should 'find a string' do
|
|
144
|
+
assert_kind_of String, subject.prop['mystring']
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
should 'find same value' do
|
|
148
|
+
assert_equal 'some data', subject.prop['mystring']
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
context 'a saved integer' do
|
|
153
|
+
subject do
|
|
154
|
+
klass = Class.new(ActiveRecord::Base) do
|
|
155
|
+
include Property
|
|
156
|
+
set_table_name :dummies
|
|
157
|
+
property.integer 'myinteger'
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
obj = klass.create('myinteger' => 789)
|
|
161
|
+
klass.find(obj)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
should 'find an integer' do
|
|
165
|
+
assert_kind_of Fixnum, subject.prop['myinteger']
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
should 'find same value' do
|
|
169
|
+
assert_equal 789, subject.prop['myinteger']
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context 'a saved float' do
|
|
174
|
+
subject do
|
|
175
|
+
klass = Class.new(ActiveRecord::Base) do
|
|
176
|
+
include Property
|
|
177
|
+
set_table_name :dummies
|
|
178
|
+
property.float 'myfloat'
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
obj = klass.create('myfloat' => 78.9)
|
|
182
|
+
klass.find(obj)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
should 'find an float' do
|
|
186
|
+
assert_kind_of Float, subject.prop['myfloat']
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
should 'find same value' do
|
|
190
|
+
assert_equal 78.9, subject.prop['myfloat']
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
context 'a saved datetime' do
|
|
195
|
+
setup do
|
|
196
|
+
@now = Time.utc(2010,02,11,17,50,18)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
subject do
|
|
200
|
+
klass = Class.new(ActiveRecord::Base) do
|
|
201
|
+
include Property
|
|
202
|
+
set_table_name :dummies
|
|
203
|
+
property.datetime 'mydatetime'
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
obj = klass.create('mydatetime' => @now)
|
|
207
|
+
klass.find(obj)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
should 'find an datetime' do
|
|
211
|
+
assert_kind_of Time, subject.prop['mydatetime']
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
should 'find same value' do
|
|
215
|
+
assert_equal @now, subject.prop['mydatetime']
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
130
220
|
context 'Setting attributes' do
|
|
131
221
|
subject { Version.new }
|
|
132
222
|
|
|
@@ -54,6 +54,7 @@ class DeclarationTest < Test::Unit::TestCase
|
|
|
54
54
|
|
|
55
55
|
context 'Property declaration' do
|
|
56
56
|
Superhero = Class.new(ActiveRecord::Base) do
|
|
57
|
+
set_table_name :dummies
|
|
57
58
|
include Property
|
|
58
59
|
end
|
|
59
60
|
|
|
@@ -132,6 +133,26 @@ class DeclarationTest < Test::Unit::TestCase
|
|
|
132
133
|
column = subject.property_columns['rolodex']
|
|
133
134
|
assert column.indexed?
|
|
134
135
|
end
|
|
136
|
+
|
|
137
|
+
context 'in an instance singleton' do
|
|
138
|
+
setup do
|
|
139
|
+
@instance = subject.new
|
|
140
|
+
@instance.property do |p|
|
|
141
|
+
p.string 'instance_only'
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
should 'behave like any other property column' do
|
|
146
|
+
@instance.attributes = {'instance_only' => 'hello'}
|
|
147
|
+
assert @instance.save
|
|
148
|
+
@instance = subject.find(@instance.id)
|
|
149
|
+
assert_equal Hash['instance_only' => 'hello'], @instance.prop
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
should 'not affect instance class' do
|
|
153
|
+
assert !subject.property_column_names.include?('instance_only')
|
|
154
|
+
end
|
|
155
|
+
end
|
|
135
156
|
end
|
|
136
157
|
|
|
137
158
|
context 'Property columns' do
|
|
@@ -62,21 +62,47 @@ class ValidationTest < Test::Unit::TestCase
|
|
|
62
62
|
|
|
63
63
|
context 'On a class with default property values' do
|
|
64
64
|
Cat = Class.new(ActiveRecord::Base) do
|
|
65
|
+
attr_accessor :encoding
|
|
66
|
+
|
|
65
67
|
set_table_name 'dummies'
|
|
66
68
|
include Property::Attribute
|
|
67
69
|
property do |p|
|
|
68
70
|
p.string 'eat', :default => 'mouse'
|
|
69
71
|
p.string 'name'
|
|
72
|
+
p.datetime 'seen_at', :default => Proc.new { Time.now }
|
|
73
|
+
p.string 'encoding', :default => :get_encoding
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def get_encoding
|
|
77
|
+
@encoding
|
|
70
78
|
end
|
|
71
79
|
end
|
|
72
80
|
|
|
73
|
-
should 'insert default values' do
|
|
81
|
+
should 'insert default literal values' do
|
|
74
82
|
subject = Cat.create
|
|
75
83
|
subject.reload
|
|
76
84
|
assert_equal 'mouse', subject.prop['eat']
|
|
77
85
|
end
|
|
78
86
|
|
|
79
|
-
should '
|
|
87
|
+
should 'call procs to get default if missing' do
|
|
88
|
+
subject = Cat.create
|
|
89
|
+
assert_kind_of Time, subject.prop['seen_at']
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
should 'call procs to get default if empty' do
|
|
93
|
+
subject = Cat.new('seen_at' => '')
|
|
94
|
+
assert_kind_of Time, subject.prop['seen_at']
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
should 'call owner methods to get default' do
|
|
98
|
+
subject = Cat.new
|
|
99
|
+
subject.encoding = 'yooupla/boom'
|
|
100
|
+
assert subject.save
|
|
101
|
+
|
|
102
|
+
assert_equal 'yooupla/boom', subject.prop['encoding']
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
should 'accept other values' do
|
|
80
106
|
subject = Cat.create('eat' => 'birds')
|
|
81
107
|
subject.reload
|
|
82
108
|
assert_equal 'birds', subject.prop['eat']
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: property
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Renaud Kern
|
|
@@ -51,6 +51,7 @@ files:
|
|
|
51
51
|
- lib/property.rb
|
|
52
52
|
- lib/property/attribute.rb
|
|
53
53
|
- lib/property/column.rb
|
|
54
|
+
- lib/property/core_ext/time.rb
|
|
54
55
|
- lib/property/declaration.rb
|
|
55
56
|
- lib/property/dirty.rb
|
|
56
57
|
- lib/property/properties.rb
|