property 2.1.0 → 2.1.1
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 +13 -1
- data/lib/property/attribute.rb +7 -6
- data/lib/property/properties.rb +19 -1
- data/lib/property/role.rb +0 -1
- data/lib/property/role_module.rb +12 -12
- data/lib/property/schema_module.rb +1 -1
- data/lib/property/stored_role.rb +0 -10
- data/lib/property/version.rb +1 -1
- data/property.gemspec +2 -2
- data/test/shoulda_macros/index.rb +13 -1
- data/test/shoulda_macros/role.rb +2 -2
- data/test/unit/property/attribute_test.rb +2 -2
- data/test/unit/property/index_simple_test.rb +4 -0
- data/test/unit/property/role_test.rb +1 -0
- data/test/unit/property/validation_test.rb +35 -5
- metadata +4 -4
data/History.txt
CHANGED
@@ -1,8 +1,20 @@
|
|
1
|
+
== 2.1.1 2010-11-23
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
* Not raising an error on invalid attributes.
|
5
|
+
* Avoid bad attributes being used to 'send' messages during error message building.
|
6
|
+
* Not setting an error for blank values.
|
7
|
+
|
8
|
+
* Minor enhancements
|
9
|
+
* Made defined_columns public.
|
10
|
+
* Fixed a bug where all columns would be parsed for each role.
|
11
|
+
* Fixed a bug where group_indices would be overwritten during initialization.
|
12
|
+
|
1
13
|
== 2.1.0 2010-11-15
|
2
14
|
|
3
15
|
* Major enhancements
|
4
16
|
* Added support for custom Schema classes through SchemaModule and StoredSchema.
|
5
|
-
|
17
|
+
|
6
18
|
== 2.0.0 2010-11-10
|
7
19
|
|
8
20
|
* Major enhancements
|
data/lib/property/attribute.rb
CHANGED
@@ -94,16 +94,17 @@ module Property
|
|
94
94
|
def attributes_with_properties=(attributes, guard_protected_attributes = true)
|
95
95
|
property_columns = schema.column_names
|
96
96
|
|
97
|
-
|
97
|
+
model_attrs = {}
|
98
98
|
|
99
99
|
attributes.keys.each do |k|
|
100
|
-
if
|
101
|
-
|
100
|
+
if respond_to?("#{k}=")
|
101
|
+
model_attrs[k] = attributes.delete(k)
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
105
|
-
|
106
|
-
self.
|
104
|
+
|
105
|
+
# Properties validation will add errors on invalid keys.
|
106
|
+
self.properties = attributes
|
107
|
+
self.attributes_without_properties = model_attrs
|
107
108
|
end
|
108
109
|
end # InstanceMethods
|
109
110
|
end # Attribute
|
data/lib/property/properties.rb
CHANGED
@@ -1,4 +1,18 @@
|
|
1
1
|
module Property
|
2
|
+
class AttributeError < ActiveRecord::Error
|
3
|
+
def default_options
|
4
|
+
options.reverse_merge :scope => [:activerecord, :errors],
|
5
|
+
:model => @base.class.human_name,
|
6
|
+
:attribute => @base.class.human_attribute_name(attribute.to_s)
|
7
|
+
end
|
8
|
+
|
9
|
+
# SECURITY: MAKE SURE WE DO NOT SEND.
|
10
|
+
# Value is already in 'options'.
|
11
|
+
def value
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
2
16
|
class Properties < Hash
|
3
17
|
attr_accessor :owner
|
4
18
|
include Property::DirtyProperties
|
@@ -49,8 +63,12 @@ module Property
|
|
49
63
|
bad_keys.each do |key|
|
50
64
|
if original_hash[key] == self[key]
|
51
65
|
# ignore invalid legacy value
|
66
|
+
elsif self[key].blank?
|
67
|
+
# ignore blank values
|
68
|
+
self.delete(key)
|
52
69
|
else
|
53
|
-
|
70
|
+
# We use our own Error class to make sure 'send' is not used on error keys.
|
71
|
+
errors.add(key, Property::AttributeError.new(@owner, key, nil, :message => 'property not declared', :value => self[key]))
|
54
72
|
end
|
55
73
|
end
|
56
74
|
|
data/lib/property/role.rb
CHANGED
data/lib/property/role_module.rb
CHANGED
@@ -74,7 +74,7 @@ module Property
|
|
74
74
|
# will be yielded with the record and should return a hash of key => value pairs.
|
75
75
|
def index(type, &block)
|
76
76
|
# type, key, proc
|
77
|
-
|
77
|
+
group_indices << [type, nil, block]
|
78
78
|
end
|
79
79
|
|
80
80
|
# Returns true if the role is used by the given object. A role is
|
@@ -90,13 +90,13 @@ module Property
|
|
90
90
|
object.properties.keys & column_names
|
91
91
|
end
|
92
92
|
|
93
|
-
# Return a list of index definitions in the form [type, key, proc_or_nil]
|
94
|
-
def
|
95
|
-
|
93
|
+
# Return a list of index definitions from the defined columns in the form [type, key, proc_or_nil]
|
94
|
+
def defined_indices
|
95
|
+
defined_columns.values.select do |c|
|
96
96
|
c.indexed?
|
97
97
|
end.map do |c|
|
98
98
|
[c.index, c.name, c.index_proc]
|
99
|
-
end +
|
99
|
+
end + group_indices
|
100
100
|
end
|
101
101
|
|
102
102
|
def inspect
|
@@ -104,14 +104,14 @@ module Property
|
|
104
104
|
"#<#{self.class}:#{sprintf("0x%x", object_id)} #{defined_columns.keys.inspect}>"
|
105
105
|
end
|
106
106
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
107
|
+
# List all property columns defined for this role
|
108
|
+
def defined_columns
|
109
|
+
@defined_columns ||= {}
|
110
|
+
end
|
111
111
|
|
112
|
-
|
113
|
-
def
|
114
|
-
@
|
112
|
+
protected
|
113
|
+
def group_indices
|
114
|
+
@group_indices ||= []
|
115
115
|
end
|
116
116
|
|
117
117
|
# @internal
|
data/lib/property/stored_role.rb
CHANGED
@@ -22,9 +22,6 @@ module Property
|
|
22
22
|
base.class_eval do
|
23
23
|
after_save :update_columns
|
24
24
|
validates_presence_of :name
|
25
|
-
def after_initialize
|
26
|
-
initialize_role_module
|
27
|
-
end
|
28
25
|
|
29
26
|
extend ClassMethods
|
30
27
|
|
@@ -45,12 +42,6 @@ module Property
|
|
45
42
|
|
46
43
|
obj
|
47
44
|
end
|
48
|
-
|
49
|
-
# Initialize a new role with the given name
|
50
|
-
def initialize(*args)
|
51
|
-
super
|
52
|
-
initialize_role_module
|
53
|
-
end
|
54
45
|
end
|
55
46
|
end # included
|
56
47
|
|
@@ -72,7 +63,6 @@ module Property
|
|
72
63
|
|
73
64
|
private
|
74
65
|
def load_columns_from_db
|
75
|
-
initialize_role_module
|
76
66
|
@columns_from_db_loaded = true
|
77
67
|
@original_columns = {}
|
78
68
|
stored_columns.each do |column|
|
data/lib/property/version.rb
CHANGED
data/property.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{property}
|
8
|
-
s.version = "2.1.
|
8
|
+
s.version = "2.1.1"
|
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"]
|
12
|
-
s.date = %q{2010-11-
|
12
|
+
s.date = %q{2010-11-23}
|
13
13
|
s.description = %q{Wrap model properties into a single database column and declare properties from within the model.}
|
14
14
|
s.email = %q{gaspard@teti.ch}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -53,7 +53,19 @@ class Test::Unit::TestCase
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
|
+
should 'build a group of indices' do
|
58
|
+
assert_equal Hash['ml_string'=>[['poem', nil]], 'integer'=>[['year', nil]]], subject.schema.index_groups
|
59
|
+
end
|
60
|
+
|
61
|
+
should 'build indices array' do
|
62
|
+
assert_equal [['integer', 'year', nil], ['ml_string', 'poem', nil]], @poet.defined_indices
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'only use defined propertys to build indices array' do
|
66
|
+
assert_equal [], subject.schema.defined_indices
|
67
|
+
end
|
68
|
+
end # assigned to an instance of Dummy
|
57
69
|
end
|
58
70
|
|
59
71
|
def self.should_not_maintain_indices
|
data/test/shoulda_macros/role.rb
CHANGED
@@ -54,10 +54,10 @@ class Test::Unit::TestCase
|
|
54
54
|
assert column.indexed?
|
55
55
|
end
|
56
56
|
|
57
|
-
should 'return a list of indices on
|
57
|
+
should 'return a list of indices on defined_indices' do
|
58
58
|
subject.property.string('rolodex', :index => true)
|
59
59
|
subject.property.integer('foobar', :index => true)
|
60
|
-
assert_equal %w{integer string}, subject.
|
60
|
+
assert_equal %w{integer string}, subject.defined_indices.map {|i| i[0].to_s }.sort
|
61
61
|
end
|
62
62
|
|
63
63
|
context 'created with a Hash' do
|
@@ -259,7 +259,7 @@ class AttributeTest < Test::Unit::TestCase
|
|
259
259
|
should 'call native methods' do
|
260
260
|
assert_equal 'please', subject.backup
|
261
261
|
end
|
262
|
-
end
|
262
|
+
end # Setting attributes
|
263
263
|
|
264
264
|
context 'Initializing an object' do
|
265
265
|
subject { Version.new('foo'=>'bar', 'title'=>'test', 'backup' => 'please') }
|
@@ -281,7 +281,7 @@ class AttributeTest < Test::Unit::TestCase
|
|
281
281
|
setup do
|
282
282
|
version = Version.create('title' => 'first', 'tic' => 'tac')
|
283
283
|
@version = Version.find(version.id)
|
284
|
-
assert subject.update_attributes(
|
284
|
+
assert subject.update_attributes(:foo=>'bar', 'title'=>'test', 'backup' => 'please')
|
285
285
|
end
|
286
286
|
|
287
287
|
subject { @version }
|
@@ -35,6 +35,10 @@ class IndexSimpleTest < ActiveSupport::TestCase
|
|
35
35
|
should 'group indices by type' do
|
36
36
|
assert_equal %w{integer special}, subject.index_groups.keys.map(&:to_s).sort
|
37
37
|
end
|
38
|
+
|
39
|
+
should 'not contain duplicates' do
|
40
|
+
assert_equal Hash["special"=>[["name", nil]], "integer"=>[["age", nil]]], subject.index_groups
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
context 'A class with a simple index definition' do
|
@@ -10,23 +10,53 @@ class ValidationTest < Test::Unit::TestCase
|
|
10
10
|
property.float 'boat'
|
11
11
|
property.string 'bird_name'
|
12
12
|
property.serialize 'cat', Cat
|
13
|
+
|
14
|
+
def infamous
|
15
|
+
raise Exception.new("Should not send!")
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
subject { Pirate.create }
|
16
20
|
|
17
21
|
context 'without a property column' do
|
18
|
-
|
19
|
-
|
22
|
+
context 'set with attributes=' do
|
23
|
+
should 'not raise an error' do
|
20
24
|
subject.update_attributes('infamous' => 'dictator')
|
21
25
|
end
|
22
|
-
end
|
23
26
|
|
24
|
-
|
27
|
+
should 'set an error message' do
|
28
|
+
subject.update_attributes('infamous' => 'dictator')
|
29
|
+
assert_equal subject.errors['infamous'], 'property not declared'
|
30
|
+
end
|
31
|
+
end # set with attributes=
|
32
|
+
|
33
|
+
should 'set an error message' do
|
25
34
|
subject.prop['infamous'] = 'dictator'
|
26
35
|
assert !subject.save
|
27
36
|
assert_equal subject.errors['infamous'], 'property not declared'
|
28
37
|
end
|
29
|
-
|
38
|
+
|
39
|
+
should 'not send to get value in error message' do
|
40
|
+
subject.prop['infamous'] = 'dictator'
|
41
|
+
assert !subject.save
|
42
|
+
assert_nothing_raised do
|
43
|
+
subject.errors.each_error do |key, error|
|
44
|
+
assert_equal 'Infamous property not declared', error.full_message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with blank value' do
|
50
|
+
|
51
|
+
should 'not set an error message' do
|
52
|
+
subject.prop['infamous'] = ''
|
53
|
+
subject.prop['greedy'] = nil
|
54
|
+
assert subject.save
|
55
|
+
assert_nil subject.errors['infamous']
|
56
|
+
assert_nil subject.errors['greedy']
|
57
|
+
end
|
58
|
+
end # with blank value
|
59
|
+
|
30
60
|
context 'with dirty' do
|
31
61
|
should 'validate if property was not changed' do
|
32
62
|
subject.prop.instance_eval do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: property
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 2.1.
|
9
|
+
- 1
|
10
|
+
version: 2.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Renaud Kern
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-11-
|
19
|
+
date: 2010-11-23 00:00:00 +01:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|