property 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,9 @@
1
- == 2.0.0
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).
@@ -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)
@@ -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 = self.schema.column_names
96
-
95
+ property_columns = schema.column_names
96
+
97
97
  properties = {}
98
98
 
99
99
  attributes.keys.each do |k|
@@ -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)} #{column_names.inspect}>"
104
+ "#<#{self.class}:#{sprintf("0x%x", object_id)} #{defined_columns.keys.inspect}>"
105
105
  end
106
106
 
107
107
  protected
@@ -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
- attr_accessor :roles, :klass
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
- @klass = opts[:class]
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Property
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{property}
8
- s.version = "2.0.0"
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-10}
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: 15
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
+ - 1
8
9
  - 0
9
- - 0
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-10 00:00:00 +01:00
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