property 0.5.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/.gitignore +2 -0
- data/History.txt +10 -0
- data/MIT-LICENSE +19 -0
- data/README.rdoc +48 -0
- data/Rakefile +51 -0
- data/generators/property/property_generator.rb +12 -0
- data/lib/property.rb +16 -0
- data/lib/property/attribute.rb +89 -0
- data/lib/property/column.rb +35 -0
- data/lib/property/declaration.rb +120 -0
- data/lib/property/dirty.rb +98 -0
- data/lib/property/properties.rb +80 -0
- data/lib/property/serialization/json.rb +38 -0
- data/lib/property/serialization/marshal.rb +35 -0
- data/lib/property/serialization/yaml.rb +29 -0
- data/test/fixtures.rb +57 -0
- data/test/shoulda_macros/serialization.rb +71 -0
- data/test/test_helper.rb +19 -0
- data/test/unit/property/attribute_test.rb +334 -0
- data/test/unit/property/declaration_test.rb +127 -0
- data/test/unit/property/dirty_test.rb +157 -0
- data/test/unit/property/validation_test.rb +97 -0
- data/test/unit/serialization/json_test.rb +12 -0
- data/test/unit/serialization/marshal_test.rb +12 -0
- data/test/unit/serialization/yaml_test.rb +12 -0
- metadata +108 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'fixtures'
|
3
|
+
|
4
|
+
class DeclarationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'A sub-class' do
|
7
|
+
context 'from a class with property columns' do
|
8
|
+
setup do
|
9
|
+
@klass = Developer
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'inherit property columsn from parent class' do
|
13
|
+
assert_equal %w{age first_name language last_name}, @klass.property_column_names.sort
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'not back-propagate definitions to parent' do
|
17
|
+
assert !@klass.superclass.property_columns.include?('language')
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'inherit current definitions from parent' do
|
21
|
+
class ParentClass < ActiveRecord::Base
|
22
|
+
include Property
|
23
|
+
property.string 'name'
|
24
|
+
end
|
25
|
+
@klass = Class.new(ParentClass) do
|
26
|
+
property.integer 'age'
|
27
|
+
end
|
28
|
+
assert_equal %w{age name}, @klass.property_column_names.sort
|
29
|
+
|
30
|
+
ParentClass.class_eval do
|
31
|
+
property.string 'first_name'
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_equal %w{age first_name name}, @klass.property_column_names.sort
|
35
|
+
end
|
36
|
+
|
37
|
+
should 'not be allowed to overwrite a property from the parent class' do
|
38
|
+
assert_raise(TypeError) do
|
39
|
+
@klass.class_eval do
|
40
|
+
property.string 'age'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'not be allowed to overwrite a property from the current class' do
|
46
|
+
assert_raise(TypeError) do
|
47
|
+
@klass.class_eval do
|
48
|
+
property.string 'language'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'Property declaration' do
|
56
|
+
Superhero = Class.new(ActiveRecord::Base) do
|
57
|
+
include Property
|
58
|
+
end
|
59
|
+
|
60
|
+
subject { Class.new(Superhero) }
|
61
|
+
|
62
|
+
should 'create Property::Column definitions' do
|
63
|
+
subject.property.string('weapon')
|
64
|
+
assert_kind_of Property::Column, subject.property_columns['weapon']
|
65
|
+
end
|
66
|
+
|
67
|
+
should 'allow string columns' do
|
68
|
+
subject.property.string('weapon')
|
69
|
+
column = subject.property_columns['weapon']
|
70
|
+
assert_equal 'weapon', column.name
|
71
|
+
assert_equal String, column.klass
|
72
|
+
assert_equal :string, column.type
|
73
|
+
end
|
74
|
+
|
75
|
+
should 'allow integer columns' do
|
76
|
+
subject.property.integer('indestructible')
|
77
|
+
column = subject.property_columns['indestructible']
|
78
|
+
assert_equal 'indestructible', column.name
|
79
|
+
assert_equal Fixnum, column.klass
|
80
|
+
assert_equal :integer, column.type
|
81
|
+
end
|
82
|
+
|
83
|
+
should 'allow float columns' do
|
84
|
+
subject.property.float('boat')
|
85
|
+
column = subject.property_columns['boat']
|
86
|
+
assert_equal 'boat', column.name
|
87
|
+
assert_equal Float, column.klass
|
88
|
+
assert_equal :float, column.type
|
89
|
+
end
|
90
|
+
|
91
|
+
should 'allow datetime columns' do
|
92
|
+
subject.property.datetime('time_weapon')
|
93
|
+
column = subject.property_columns['time_weapon']
|
94
|
+
assert_equal 'time_weapon', column.name
|
95
|
+
assert_equal Time, column.klass
|
96
|
+
assert_equal :datetime, column.type
|
97
|
+
end
|
98
|
+
|
99
|
+
should 'allow default value option' do
|
100
|
+
subject.property.integer('force', :default => 10)
|
101
|
+
column = subject.property_columns['force']
|
102
|
+
assert_equal 10, column.default
|
103
|
+
end
|
104
|
+
|
105
|
+
should 'allow indexed option' do
|
106
|
+
subject.property.string('rolodex', :indexed => true)
|
107
|
+
column = subject.property_columns['rolodex']
|
108
|
+
assert column.indexed?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'Property columns' do
|
113
|
+
Dummy = Class.new(ActiveRecord::Base) do
|
114
|
+
set_table_name 'dummies'
|
115
|
+
include Property
|
116
|
+
end
|
117
|
+
|
118
|
+
should 'return empty Hash if no property columsn are declared' do
|
119
|
+
assert_equal Hash[], Dummy.property_columns
|
120
|
+
end
|
121
|
+
|
122
|
+
should 'return list of property columns from class' do
|
123
|
+
assert_kind_of Hash, Employee.property_columns
|
124
|
+
assert_kind_of Property::Column, Employee.property_columns['first_name']
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'fixtures'
|
3
|
+
|
4
|
+
class DirtyTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def self.should_behave_nice_after_save(bar_value)
|
7
|
+
context 'after save' do
|
8
|
+
setup do
|
9
|
+
subject.save
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'return empty hash with changes' do
|
13
|
+
assert_equal Hash[], subject.changes
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'return empty hash on properties.changes' do
|
17
|
+
assert_equal Hash[], subject.properties.changes
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'return false on properties.key_changed?' do
|
21
|
+
assert !subject.properties.foo_changed?
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'return current value on properties.key_was' do
|
25
|
+
assert_equal bar_value, subject.properties.foo_was
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'On a dirty object' do
|
31
|
+
setup do
|
32
|
+
@version = Version.create('title'=>'test', 'foo'=>'bar', 'tic'=>'tac')
|
33
|
+
end
|
34
|
+
|
35
|
+
subject { @version }
|
36
|
+
|
37
|
+
context 'with changed properties' do
|
38
|
+
setup do
|
39
|
+
subject.properties = {'foo'=>'barre', 'tic'=>'taaac'}
|
40
|
+
end
|
41
|
+
|
42
|
+
should_behave_nice_after_save('barre')
|
43
|
+
|
44
|
+
should 'return true on properties.changed?' do
|
45
|
+
assert subject.properties.changed?
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'return true on changed?' do
|
49
|
+
assert subject.changed?
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'return changed properties with :changed' do
|
53
|
+
assert_equal %w{foo tic}, subject.changed.sort
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'return changed properties with properties.changed' do
|
57
|
+
assert_equal %w{foo tic}, subject.properties.changed.sort
|
58
|
+
end
|
59
|
+
|
60
|
+
should 'return property changes with changes' do
|
61
|
+
assert_equal Hash['tic'=>['tac', 'taaac'], 'foo'=>['bar', 'barre']], subject.changes
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'return property changes with properties.changes' do
|
65
|
+
assert_equal Hash['tic'=>['tac', 'taaac'], 'foo'=>['bar', 'barre']], subject.properties.changes
|
66
|
+
end
|
67
|
+
|
68
|
+
should 'return true on properties.key_changed?' do
|
69
|
+
assert subject.properties.foo_changed?
|
70
|
+
end
|
71
|
+
|
72
|
+
should 'return previous value on properties.key_was' do
|
73
|
+
assert_equal 'bar', subject.properties.foo_was
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with changed native attributes' do
|
78
|
+
setup do
|
79
|
+
subject.title = 'Levinas'
|
80
|
+
end
|
81
|
+
|
82
|
+
should_behave_nice_after_save('bar')
|
83
|
+
|
84
|
+
should 'return false on properties.changed?' do
|
85
|
+
assert !subject.properties.changed?
|
86
|
+
end
|
87
|
+
|
88
|
+
should 'return true on changed?' do
|
89
|
+
assert subject.changed?
|
90
|
+
end
|
91
|
+
|
92
|
+
should 'return changed attributes with :changed' do
|
93
|
+
assert_equal ['title'], subject.changed.sort
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'return empty list with properties.changed' do
|
97
|
+
assert_equal [], subject.properties.changed.sort
|
98
|
+
end
|
99
|
+
|
100
|
+
should 'return attributes changes with changes' do
|
101
|
+
assert_equal Hash['title'=>['test', 'Levinas']], subject.changes
|
102
|
+
end
|
103
|
+
|
104
|
+
should 'return empty hash on properties.changes' do
|
105
|
+
assert_equal Hash[], subject.properties.changes
|
106
|
+
end
|
107
|
+
|
108
|
+
should 'return false on properties.key_changed?' do
|
109
|
+
assert !subject.properties.foo_changed?
|
110
|
+
end
|
111
|
+
|
112
|
+
should 'return current value on properties.key_was' do
|
113
|
+
assert_equal 'bar', subject.properties.foo_was
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with changed native attributes and properties' do
|
118
|
+
setup do
|
119
|
+
subject.attributes = {'title' => 'Ricœur', 'foo'=>'barre', 'tic'=>'taaac'}
|
120
|
+
end
|
121
|
+
|
122
|
+
should_behave_nice_after_save('barre')
|
123
|
+
|
124
|
+
should 'return true on properties.changed?' do
|
125
|
+
assert subject.properties.changed?
|
126
|
+
end
|
127
|
+
|
128
|
+
should 'return true on changed?' do
|
129
|
+
assert subject.changed?
|
130
|
+
end
|
131
|
+
|
132
|
+
should 'return changed properties and attributes with :changed' do
|
133
|
+
assert_equal %w{foo tic title}, subject.changed.sort
|
134
|
+
end
|
135
|
+
|
136
|
+
should 'return changed properties with properties.changed' do
|
137
|
+
assert_equal %w{foo tic}, subject.properties.changed.sort
|
138
|
+
end
|
139
|
+
|
140
|
+
should 'return attributes and properties changes with changes' do
|
141
|
+
assert_equal Hash['tic'=>['tac', 'taaac'], 'foo'=>['bar', 'barre'], 'title' => ['test', 'Ricœur']], subject.changes
|
142
|
+
end
|
143
|
+
|
144
|
+
should 'return property changes with properties.changes' do
|
145
|
+
assert_equal Hash['tic'=>['tac', 'taaac'], 'foo'=>['bar', 'barre']], subject.properties.changes
|
146
|
+
end
|
147
|
+
|
148
|
+
should 'return true on properties.key_changed?' do
|
149
|
+
assert subject.properties.foo_changed?
|
150
|
+
end
|
151
|
+
|
152
|
+
should 'return previous value on properties.key_was' do
|
153
|
+
assert_equal 'bar', subject.properties.foo_was
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'fixtures'
|
3
|
+
|
4
|
+
class ValidationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'When setting a property' do
|
7
|
+
Pirate = Class.new(ActiveRecord::Base) do
|
8
|
+
set_table_name 'dummies'
|
9
|
+
include Property
|
10
|
+
property.float 'boat'
|
11
|
+
property.string 'bird_name'
|
12
|
+
end
|
13
|
+
|
14
|
+
subject { Pirate.create }
|
15
|
+
|
16
|
+
context 'without a property column' do
|
17
|
+
setup do
|
18
|
+
assert !subject.update_attributes('honest' => 'man')
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'render object invalid' do
|
22
|
+
assert subject.invalid?
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'set an error message on the property' do
|
26
|
+
assert_contains subject.errors.full_messages, 'Honest property is not declared'
|
27
|
+
assert_equal subject.errors['honest'], 'property is not declared'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'from the wrong data type' do
|
32
|
+
setup do
|
33
|
+
subject.update_attributes('boat' => Time.now, 'bird_name' => 1337)
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'cast the data type' do
|
37
|
+
assert subject.valid?
|
38
|
+
assert_kind_of Float, subject.prop['boat']
|
39
|
+
assert_kind_of String, subject.prop['bird_name']
|
40
|
+
assert_equal '1337', subject.prop['bird_name']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'to a blank value' do
|
45
|
+
subject { Pirate.create('bird_name' => 'Rainbow Lorikeet') }
|
46
|
+
|
47
|
+
should 'accept nil' do
|
48
|
+
assert subject.update_attributes('bird_name' => nil)
|
49
|
+
end
|
50
|
+
|
51
|
+
should 'accept empty string' do
|
52
|
+
assert subject.update_attributes('bird_name' => '')
|
53
|
+
end
|
54
|
+
|
55
|
+
should 'clear property if there is no default' do
|
56
|
+
subject.update_attributes('bird_name' => '')
|
57
|
+
assert_nil subject.properties['bird_name']
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end # When setting a property
|
62
|
+
|
63
|
+
context 'On a class with default property values' do
|
64
|
+
Cat = Class.new(ActiveRecord::Base) do
|
65
|
+
set_table_name 'dummies'
|
66
|
+
include Property::Attribute
|
67
|
+
property do |p|
|
68
|
+
p.string 'eat', :default => 'mouse'
|
69
|
+
p.string 'name'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'insert default values' do
|
74
|
+
subject = Cat.create
|
75
|
+
subject.reload
|
76
|
+
assert_equal 'mouse', subject.prop['eat']
|
77
|
+
end
|
78
|
+
|
79
|
+
should 'insert accept other values' do
|
80
|
+
subject = Cat.create('eat' => 'birds')
|
81
|
+
subject.reload
|
82
|
+
assert_equal 'birds', subject.prop['eat']
|
83
|
+
end
|
84
|
+
|
85
|
+
should 'revert to default value when set to empty string' do
|
86
|
+
subject = Cat.create('eat' => 'birds')
|
87
|
+
subject.update_attributes('eat' => '')
|
88
|
+
assert_equal 'mouse', subject.prop['eat']
|
89
|
+
end
|
90
|
+
|
91
|
+
should 'revert to default value when set to nil' do
|
92
|
+
subject = Cat.create('eat' => 'birds')
|
93
|
+
subject.update_attributes('eat' => nil)
|
94
|
+
assert_equal 'mouse', subject.prop['eat']
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: property
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Renaud Kern
|
8
|
+
- Gaspard Bucher
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-02-11 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: shoulda
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: active_record
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
version:
|
36
|
+
description: Wrap model properties into a single database column and declare properties from within the model.
|
37
|
+
email: gaspard@teti.ch
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- History.txt
|
47
|
+
- MIT-LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- generators/property/property_generator.rb
|
51
|
+
- lib/property.rb
|
52
|
+
- lib/property/attribute.rb
|
53
|
+
- lib/property/column.rb
|
54
|
+
- lib/property/declaration.rb
|
55
|
+
- lib/property/dirty.rb
|
56
|
+
- lib/property/properties.rb
|
57
|
+
- lib/property/serialization/json.rb
|
58
|
+
- lib/property/serialization/marshal.rb
|
59
|
+
- lib/property/serialization/yaml.rb
|
60
|
+
- test/fixtures.rb
|
61
|
+
- test/shoulda_macros/serialization.rb
|
62
|
+
- test/test_helper.rb
|
63
|
+
- test/unit/property/attribute_test.rb
|
64
|
+
- test/unit/property/declaration_test.rb
|
65
|
+
- test/unit/property/dirty_test.rb
|
66
|
+
- test/unit/property/validation_test.rb
|
67
|
+
- test/unit/serialization/json_test.rb
|
68
|
+
- test/unit/serialization/marshal_test.rb
|
69
|
+
- test/unit/serialization/yaml_test.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://zenadmin.org/635
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
version:
|
91
|
+
requirements: []
|
92
|
+
|
93
|
+
rubyforge_project: property
|
94
|
+
rubygems_version: 1.3.5
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: model properties wrap into a single database column
|
98
|
+
test_files:
|
99
|
+
- test/fixtures.rb
|
100
|
+
- test/shoulda_macros/serialization.rb
|
101
|
+
- test/test_helper.rb
|
102
|
+
- test/unit/property/attribute_test.rb
|
103
|
+
- test/unit/property/declaration_test.rb
|
104
|
+
- test/unit/property/dirty_test.rb
|
105
|
+
- test/unit/property/validation_test.rb
|
106
|
+
- test/unit/serialization/json_test.rb
|
107
|
+
- test/unit/serialization/marshal_test.rb
|
108
|
+
- test/unit/serialization/yaml_test.rb
|