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.
@@ -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