property 2.0.0 → 2.1.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 -1
- data/lib/property.rb +2 -0
- data/lib/property/attribute.rb +2 -2
- data/lib/property/role_module.rb +1 -1
- data/lib/property/schema.rb +2 -84
- data/lib/property/schema_module.rb +99 -0
- data/lib/property/stored_role.rb +5 -1
- data/lib/property/stored_schema.rb +20 -0
- data/lib/property/version.rb +1 -1
- data/property.gemspec +4 -2
- data/test/unit/property/stored_role_test.rb +9 -85
- metadata +6 -4
data/History.txt
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
== 2.
|
1
|
+
== 2.1.0 2010-11-15
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
* Added support for custom Schema classes through SchemaModule and StoredSchema.
|
5
|
+
|
6
|
+
== 2.0.0 2010-11-10
|
2
7
|
|
3
8
|
* Major enhancements
|
4
9
|
* Rewrite of the core engine to remove all the metaclass and anonymous module codes (generated memory leaks).
|
data/lib/property.rb
CHANGED
@@ -3,6 +3,7 @@ require 'property/dirty'
|
|
3
3
|
require 'property/properties'
|
4
4
|
require 'property/column'
|
5
5
|
require 'property/role_module'
|
6
|
+
require 'property/schema_module'
|
6
7
|
require 'property/role'
|
7
8
|
require 'property/schema'
|
8
9
|
require 'property/declaration'
|
@@ -12,6 +13,7 @@ require 'property/serialization/json'
|
|
12
13
|
require 'property/core_ext/time'
|
13
14
|
require 'property/base'
|
14
15
|
require 'property/stored_role'
|
16
|
+
require 'property/stored_schema'
|
15
17
|
|
16
18
|
module Property
|
17
19
|
def self.included(base)
|
data/lib/property/attribute.rb
CHANGED
@@ -92,8 +92,8 @@ module Property
|
|
92
92
|
|
93
93
|
private
|
94
94
|
def attributes_with_properties=(attributes, guard_protected_attributes = true)
|
95
|
-
property_columns =
|
96
|
-
|
95
|
+
property_columns = schema.column_names
|
96
|
+
|
97
97
|
properties = {}
|
98
98
|
|
99
99
|
attributes.keys.each do |k|
|
data/lib/property/role_module.rb
CHANGED
@@ -101,7 +101,7 @@ module Property
|
|
101
101
|
|
102
102
|
def inspect
|
103
103
|
# "#<#{self.class}:#{sprintf("0x%x", object_id)} #{@name.inspect} @klass = #{@klass.inspect} @defined_columns = #{@defined_columns.inspect}>"
|
104
|
-
"#<#{self.class}:#{sprintf("0x%x", object_id)} #{
|
104
|
+
"#<#{self.class}:#{sprintf("0x%x", object_id)} #{defined_columns.keys.inspect}>"
|
105
105
|
end
|
106
106
|
|
107
107
|
protected
|
data/lib/property/schema.rb
CHANGED
@@ -2,95 +2,13 @@ module Property
|
|
2
2
|
# A schema contains all the property definitions for a given class. If Role is a module,
|
3
3
|
# then schema is a Class.
|
4
4
|
class Schema < Role
|
5
|
-
|
5
|
+
include Property::SchemaModule
|
6
6
|
|
7
7
|
# Initialize a new schema with a name and the klass linked to the schema.
|
8
8
|
def initialize(name, opts = {})
|
9
9
|
super
|
10
|
-
|
11
|
-
|
12
|
-
@roles = [self]
|
13
|
-
|
14
|
-
# Schema inheritance
|
15
|
-
unless superschema = opts[:superschema]
|
16
|
-
if @klass && @klass.superclass.respond_to?(:schema)
|
17
|
-
superschema = @klass.superclass.schema
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
if superschema
|
22
|
-
include_role superschema
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Add a set of property definitions to the schema.
|
27
|
-
def include_role(role)
|
28
|
-
@columns = nil # clear cache
|
29
|
-
if role.kind_of?(Schema)
|
30
|
-
# Superclass inheritance
|
31
|
-
@roles << role.roles
|
32
|
-
elsif role.kind_of?(RoleModule)
|
33
|
-
@roles << role
|
34
|
-
elsif role.respond_to?(:schema) && role.schema.kind_of?(Role)
|
35
|
-
@roles << role.schema.roles
|
36
|
-
else
|
37
|
-
raise TypeError.new("Cannot include role #{role} (invalid type).")
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Return a hash with indexed types as keys and index definitions as values.
|
42
|
-
def index_groups
|
43
|
-
index_groups = {}
|
44
|
-
@roles.flatten.uniq.each do |b|
|
45
|
-
b.indices.each do |list|
|
46
|
-
(index_groups[list.first] ||= []) << list[1..-1]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
index_groups
|
10
|
+
initialize_schema_module(opts)
|
50
11
|
end
|
51
12
|
|
52
|
-
# Return a hash with the column definitions defined in the schema and in the included
|
53
|
-
# roles.
|
54
|
-
def columns
|
55
|
-
# FIXME: can we memoize this list on the first call ? Do we need to update properties after such a call ?
|
56
|
-
# @columns ||=
|
57
|
-
begin
|
58
|
-
res = {}
|
59
|
-
@roles.flatten.uniq.each do |role|
|
60
|
-
# TODO: we could check for property redefinitions.
|
61
|
-
res.merge!(role.defined_columns)
|
62
|
-
end
|
63
|
-
res
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# Return the list of active roles. The active roles are all the Roles included
|
68
|
-
# in the current object for which properties have been defined (not blank).
|
69
|
-
def used_roles_in(object)
|
70
|
-
roles.flatten.uniq.select do |role|
|
71
|
-
role.used_in(object)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Return true if the role has been included or is included in any superclass.
|
76
|
-
def has_role?(role)
|
77
|
-
if role.kind_of?(Schema)
|
78
|
-
role.roles.flatten - @roles.flatten == []
|
79
|
-
elsif role.kind_of?(RoleModule)
|
80
|
-
@roles.flatten.include?(role)
|
81
|
-
elsif role.respond_to?(:schema) && role.schema.kind_of?(Role)
|
82
|
-
has_role?(role.schema)
|
83
|
-
else
|
84
|
-
false
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# When a column is added in a Schema: define accessors in related class
|
89
|
-
def add_column(column)
|
90
|
-
super
|
91
|
-
if @klass
|
92
|
-
@klass.define_property_methods(column) if column.should_create_accessors?
|
93
|
-
end
|
94
|
-
end
|
95
13
|
end
|
96
14
|
end # Property
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Property
|
2
|
+
# The SchemaModule enables a class to act as a Schema.
|
3
|
+
module SchemaModule
|
4
|
+
def initialize_schema_module(opts)
|
5
|
+
@klass = opts[:class]
|
6
|
+
|
7
|
+
@roles = [self]
|
8
|
+
|
9
|
+
# Schema inheritance
|
10
|
+
unless superschema = opts[:superschema]
|
11
|
+
if @klass && @klass.superclass.respond_to?(:schema)
|
12
|
+
superschema = @klass.superclass.schema
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
if superschema
|
17
|
+
include_role superschema
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def klass
|
22
|
+
@klass
|
23
|
+
end
|
24
|
+
|
25
|
+
def roles
|
26
|
+
@roles
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add a set of property definitions to the schema.
|
30
|
+
def include_role(role)
|
31
|
+
# @columns = nil # clear cache
|
32
|
+
if role.kind_of?(SchemaModule)
|
33
|
+
# Superclass inheritance
|
34
|
+
@roles << role.roles
|
35
|
+
elsif role.kind_of?(RoleModule)
|
36
|
+
@roles << role
|
37
|
+
elsif role.respond_to?(:schema) && role.schema.kind_of?(Role)
|
38
|
+
@roles << role.schema.roles
|
39
|
+
else
|
40
|
+
raise TypeError.new("Cannot include role #{role} (invalid type).")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return a hash with indexed types as keys and index definitions as values.
|
45
|
+
def index_groups
|
46
|
+
index_groups = {}
|
47
|
+
@roles.flatten.uniq.each do |b|
|
48
|
+
b.indices.each do |list|
|
49
|
+
(index_groups[list.first] ||= []) << list[1..-1]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
index_groups
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return a hash with the column definitions defined in the schema and in the included
|
56
|
+
# roles.
|
57
|
+
def columns
|
58
|
+
# FIXME: can we memoize this list on the first call ? Do we need to update properties after such a call ?
|
59
|
+
# @columns ||=
|
60
|
+
begin
|
61
|
+
res = {}
|
62
|
+
@roles.flatten.uniq.each do |role|
|
63
|
+
# TODO: we could check for property redefinitions.
|
64
|
+
res.merge!(role.defined_columns)
|
65
|
+
end
|
66
|
+
res
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return the list of active roles. The active roles are all the Roles included
|
71
|
+
# in the current object for which properties have been defined (not blank).
|
72
|
+
def used_roles_in(object)
|
73
|
+
roles.flatten.uniq.select do |role|
|
74
|
+
role.used_in(object)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return true if the role has been included or is included in any superclass.
|
79
|
+
def has_role?(role)
|
80
|
+
if role.kind_of?(Schema)
|
81
|
+
role.roles.flatten - @roles.flatten == []
|
82
|
+
elsif role.kind_of?(RoleModule)
|
83
|
+
@roles.flatten.include?(role)
|
84
|
+
elsif role.respond_to?(:schema) && role.schema.kind_of?(Role)
|
85
|
+
has_role?(role.schema)
|
86
|
+
else
|
87
|
+
false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# When a column is added in a Schema: define accessors in related class
|
92
|
+
def add_column(column)
|
93
|
+
super
|
94
|
+
if @klass
|
95
|
+
@klass.define_property_methods(column) if column.should_create_accessors?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end # SchemaModule
|
99
|
+
end # Property
|
data/lib/property/stored_role.rb
CHANGED
@@ -22,6 +22,10 @@ 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
|
extend ClassMethods
|
26
30
|
|
27
31
|
def self.new(arg, &block)
|
@@ -59,7 +63,7 @@ module Property
|
|
59
63
|
def property
|
60
64
|
super
|
61
65
|
end
|
62
|
-
|
66
|
+
|
63
67
|
# Overwrite name reader in RoleModule
|
64
68
|
def name
|
65
69
|
self[:name]
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'property/role_module'
|
2
|
+
require 'property/stored_column'
|
3
|
+
|
4
|
+
module Property
|
5
|
+
# This module lets you use a custom class to store a schema inside
|
6
|
+
# the database. The custom class must also include StoredRole.
|
7
|
+
module StoredSchema
|
8
|
+
include SchemaModule
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.class_eval do
|
12
|
+
attr_writer :class, :superschema
|
13
|
+
|
14
|
+
def after_initialize
|
15
|
+
initialize_schema_module(:class => @class, :superschema => @superschema)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
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.
|
8
|
+
s.version = "2.1.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"]
|
12
|
-
s.date = %q{2010-11-
|
12
|
+
s.date = %q{2010-11-15}
|
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 = [
|
@@ -38,11 +38,13 @@ Gem::Specification.new do |s|
|
|
38
38
|
"lib/property/role.rb",
|
39
39
|
"lib/property/role_module.rb",
|
40
40
|
"lib/property/schema.rb",
|
41
|
+
"lib/property/schema_module.rb",
|
41
42
|
"lib/property/serialization/json.rb",
|
42
43
|
"lib/property/serialization/marshal.rb",
|
43
44
|
"lib/property/serialization/yaml.rb",
|
44
45
|
"lib/property/stored_column.rb",
|
45
46
|
"lib/property/stored_role.rb",
|
47
|
+
"lib/property/stored_schema.rb",
|
46
48
|
"lib/property/version.rb",
|
47
49
|
"property.gemspec",
|
48
50
|
"test/database.rb",
|
@@ -10,8 +10,16 @@ class StoredRoleTest < ActiveSupport::TestCase
|
|
10
10
|
include Property::StoredRole
|
11
11
|
stored_columns_class 'StoredRoleTest::Column'
|
12
12
|
end
|
13
|
+
|
14
|
+
class Schema < Role
|
15
|
+
include Property::StoredSchema
|
16
|
+
end
|
13
17
|
|
14
18
|
should_store_property_definitions(Role)
|
19
|
+
|
20
|
+
context 'A Schema class' do
|
21
|
+
should_store_property_definitions(Schema)
|
22
|
+
end
|
15
23
|
|
16
24
|
context 'A stored Role' do
|
17
25
|
|
@@ -24,92 +32,8 @@ class StoredRoleTest < ActiveSupport::TestCase
|
|
24
32
|
@poet = Role.find(role.id)
|
25
33
|
end
|
26
34
|
|
35
|
+
should_insert_properties_on_include_role_poet
|
27
36
|
|
28
|
-
# ========================== should_insert_properties_on_include_role_poet
|
29
|
-
|
30
|
-
context 'added' do
|
31
|
-
|
32
|
-
context 'to a parent class' do
|
33
|
-
setup do
|
34
|
-
@parent = Class.new(ActiveRecord::Base) do
|
35
|
-
set_table_name :dummies
|
36
|
-
include Property
|
37
|
-
property.string 'name'
|
38
|
-
|
39
|
-
def muse
|
40
|
-
'I am your muse'
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
@klass = Class.new(@parent)
|
45
|
-
end
|
46
|
-
|
47
|
-
should 'propagate definitions to child' do
|
48
|
-
@parent.include_role @poet
|
49
|
-
assert_equal %w{name poem year}, @klass.schema.column_names.sort
|
50
|
-
end
|
51
|
-
|
52
|
-
should 'return true on has_role?' do
|
53
|
-
@parent.include_role @poet
|
54
|
-
assert @klass.has_role?(@poet)
|
55
|
-
end
|
56
|
-
|
57
|
-
should 'not raise an exception on double inclusion' do
|
58
|
-
@parent.include_role @poet
|
59
|
-
assert_nothing_raised { @parent.include_role @poet }
|
60
|
-
end
|
61
|
-
|
62
|
-
should 'add accessor methods to child' do
|
63
|
-
subject = @klass.new
|
64
|
-
assert_raises(NoMethodError) { subject.poem = 'Poe'}
|
65
|
-
@parent.include_role @poet
|
66
|
-
|
67
|
-
assert_nothing_raised { subject.poem = 'Poe'}
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'to a class' do
|
72
|
-
setup do
|
73
|
-
@klass = Class.new(ActiveRecord::Base) do
|
74
|
-
set_table_name :dummies
|
75
|
-
include Property
|
76
|
-
property.string 'name'
|
77
|
-
|
78
|
-
def muse
|
79
|
-
'I am your muse'
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
should 'insert definitions' do
|
85
|
-
@klass.include_role @poet
|
86
|
-
assert_equal %w{name poem year}, @klass.schema.column_names.sort
|
87
|
-
end
|
88
|
-
|
89
|
-
should 'return true on class has_role?' do
|
90
|
-
@klass.include_role @poet
|
91
|
-
assert @klass.has_role?(@poet)
|
92
|
-
end
|
93
|
-
|
94
|
-
should 'return role from column' do
|
95
|
-
@klass.include_role @poet
|
96
|
-
assert_equal (@poet.kind_of?(Class) ? @poet.schema : @poet), @klass.schema.columns['poem'].role
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
context 'to an instance' do
|
101
|
-
subject { Developer.new }
|
102
|
-
|
103
|
-
setup do
|
104
|
-
subject.include_role @poet
|
105
|
-
end
|
106
|
-
|
107
|
-
should 'merge property definitions' do
|
108
|
-
assert_equal %w{age first_name language last_name poem year}, subject.schema.column_names.sort
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
# ==========================
|
113
37
|
should_take_part_in_used_list(false)
|
114
38
|
should_not_maintain_indices # no indexed column defined
|
115
39
|
|
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: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 2.0.0
|
10
|
+
version: 2.1.0
|
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-15 00:00:00 +01:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -78,11 +78,13 @@ files:
|
|
78
78
|
- lib/property/role.rb
|
79
79
|
- lib/property/role_module.rb
|
80
80
|
- lib/property/schema.rb
|
81
|
+
- lib/property/schema_module.rb
|
81
82
|
- lib/property/serialization/json.rb
|
82
83
|
- lib/property/serialization/marshal.rb
|
83
84
|
- lib/property/serialization/yaml.rb
|
84
85
|
- lib/property/stored_column.rb
|
85
86
|
- lib/property/stored_role.rb
|
87
|
+
- lib/property/stored_schema.rb
|
86
88
|
- lib/property/version.rb
|
87
89
|
- property.gemspec
|
88
90
|
- test/database.rb
|