property 0.9.1 → 1.0.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 +1 -0
- data/History.txt +19 -3
- data/README.rdoc +51 -6
- data/lib/property.rb +4 -2
- data/lib/property/attribute.rb +14 -7
- data/lib/property/base.rb +16 -0
- data/lib/property/column.rb +13 -1
- data/lib/property/declaration.rb +48 -26
- data/lib/property/error.rb +4 -0
- data/lib/property/index.rb +104 -29
- data/lib/property/properties.rb +7 -1
- data/lib/property/redefined_method_error.rb +8 -0
- data/lib/property/redefined_property_error.rb +8 -0
- data/lib/property/role.rb +30 -0
- data/lib/property/{behavior.rb → role_module.rb} +67 -35
- data/lib/property/schema.rb +76 -32
- data/lib/property/stored_column.rb +30 -0
- data/lib/property/stored_role.rb +101 -0
- data/property.gemspec +20 -5
- data/test/fixtures.rb +39 -1
- data/test/shoulda_macros/index.rb +95 -0
- data/test/shoulda_macros/role.rb +237 -0
- data/test/shoulda_macros/serialization.rb +1 -1
- data/test/test_helper.rb +2 -0
- data/test/unit/property/base_test.rb +80 -0
- data/test/unit/property/declaration_test.rb +89 -30
- data/test/unit/property/index_foreign_test.rb +2 -2
- data/test/unit/property/index_simple_test.rb +17 -4
- data/test/unit/property/role_test.rb +78 -0
- data/test/unit/property/stored_role_test.rb +84 -0
- data/test/unit/property/validation_test.rb +26 -4
- metadata +22 -7
- data/test/unit/property/behavior_test.rb +0 -146
@@ -0,0 +1,101 @@
|
|
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 set of property definitions inside
|
6
|
+
# the database. For the rest, this class behaves just like Role.
|
7
|
+
#
|
8
|
+
# Once this module is included, you need to set the has_many association to the class that
|
9
|
+
# contains the columns definitions with something like:
|
10
|
+
#
|
11
|
+
# has_many :stored_columns, :class_name => NameOfColumnsClass
|
12
|
+
module StoredRole
|
13
|
+
include RoleModule
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def stored_columns_class(columns_class)
|
17
|
+
has_many :stored_columns, :class_name => columns_class
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
base.class_eval do
|
23
|
+
after_save :update_columns
|
24
|
+
validates_presence_of :name
|
25
|
+
extend ClassMethods
|
26
|
+
|
27
|
+
def self.new(arg, &block)
|
28
|
+
unless arg.kind_of?(Hash)
|
29
|
+
arg = {:name => arg}
|
30
|
+
end
|
31
|
+
|
32
|
+
if block_given?
|
33
|
+
obj = super(arg) do
|
34
|
+
# Dummy block to hide our special property declaration block
|
35
|
+
end
|
36
|
+
|
37
|
+
obj.property(&block)
|
38
|
+
else
|
39
|
+
obj = super(arg)
|
40
|
+
end
|
41
|
+
|
42
|
+
obj
|
43
|
+
end
|
44
|
+
|
45
|
+
# Initialize a new role with the given name
|
46
|
+
def initialize(*args)
|
47
|
+
super
|
48
|
+
initialize_role_module
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end # included
|
52
|
+
|
53
|
+
# List all property definitions for the current role
|
54
|
+
def columns
|
55
|
+
load_columns_from_db unless @columns_from_db_loaded
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
def property
|
60
|
+
initialize_role_module unless @accessor_module
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
private
|
66
|
+
def load_columns_from_db
|
67
|
+
initialize_role_module
|
68
|
+
@columns_from_db_loaded = true
|
69
|
+
@original_columns = {}
|
70
|
+
stored_columns.each do |column|
|
71
|
+
@original_columns[column.name] = column
|
72
|
+
add_column(Property::Column.new(column.name, column.default, column.ptype, column.options))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def update_columns
|
77
|
+
@original_columns ||= {}
|
78
|
+
stored_column_names = @original_columns.keys
|
79
|
+
defined_column_names = self.column_names
|
80
|
+
|
81
|
+
new_columns = defined_column_names - stored_column_names
|
82
|
+
updated_columns = defined_column_names & stored_column_names
|
83
|
+
# Not needed: there is no way to remove a property right now
|
84
|
+
# deleted_columns = stored_column_names - defined_column_names
|
85
|
+
|
86
|
+
new_columns.each do |name|
|
87
|
+
ActiveRecord::Base.logger.warn "Creating #{name} column"
|
88
|
+
stored_columns.create(:name => name, :ptype => columns[name].type.to_s)
|
89
|
+
end
|
90
|
+
|
91
|
+
updated_columns.each do |name|
|
92
|
+
@original_columns[name].update_attributes(:name => name, :ptype => columns[name].type.to_s)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Not needed: there is no way to remove a property right now
|
96
|
+
# deleted_columns.each do |name|
|
97
|
+
# @original_columns[name].destroy!
|
98
|
+
# end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
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 = "0.
|
8
|
+
s.version = "1.0.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-
|
12
|
+
s.date = %q{2010-05-27}
|
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 = [
|
@@ -24,30 +24,41 @@ Gem::Specification.new do |s|
|
|
24
24
|
"generators/property/property_generator.rb",
|
25
25
|
"lib/property.rb",
|
26
26
|
"lib/property/attribute.rb",
|
27
|
-
"lib/property/
|
27
|
+
"lib/property/base.rb",
|
28
28
|
"lib/property/column.rb",
|
29
29
|
"lib/property/core_ext/time.rb",
|
30
30
|
"lib/property/db.rb",
|
31
31
|
"lib/property/declaration.rb",
|
32
32
|
"lib/property/dirty.rb",
|
33
|
+
"lib/property/error.rb",
|
33
34
|
"lib/property/index.rb",
|
34
35
|
"lib/property/properties.rb",
|
36
|
+
"lib/property/redefined_method_error.rb",
|
37
|
+
"lib/property/redefined_property_error.rb",
|
38
|
+
"lib/property/role.rb",
|
39
|
+
"lib/property/role_module.rb",
|
35
40
|
"lib/property/schema.rb",
|
36
41
|
"lib/property/serialization/json.rb",
|
37
42
|
"lib/property/serialization/marshal.rb",
|
38
43
|
"lib/property/serialization/yaml.rb",
|
44
|
+
"lib/property/stored_column.rb",
|
45
|
+
"lib/property/stored_role.rb",
|
39
46
|
"property.gemspec",
|
40
47
|
"test/fixtures.rb",
|
48
|
+
"test/shoulda_macros/index.rb",
|
49
|
+
"test/shoulda_macros/role.rb",
|
41
50
|
"test/shoulda_macros/serialization.rb",
|
42
51
|
"test/test_helper.rb",
|
43
52
|
"test/unit/property/attribute_test.rb",
|
44
|
-
"test/unit/property/
|
53
|
+
"test/unit/property/base_test.rb",
|
45
54
|
"test/unit/property/declaration_test.rb",
|
46
55
|
"test/unit/property/dirty_test.rb",
|
47
56
|
"test/unit/property/index_complex_test.rb",
|
48
57
|
"test/unit/property/index_custom_test.rb",
|
49
58
|
"test/unit/property/index_foreign_test.rb",
|
50
59
|
"test/unit/property/index_simple_test.rb",
|
60
|
+
"test/unit/property/role_test.rb",
|
61
|
+
"test/unit/property/stored_role_test.rb",
|
51
62
|
"test/unit/property/validation_test.rb",
|
52
63
|
"test/unit/serialization/json_test.rb",
|
53
64
|
"test/unit/serialization/marshal_test.rb",
|
@@ -61,16 +72,20 @@ Gem::Specification.new do |s|
|
|
61
72
|
s.summary = %q{model properties wrap into a single database column}
|
62
73
|
s.test_files = [
|
63
74
|
"test/fixtures.rb",
|
75
|
+
"test/shoulda_macros/index.rb",
|
76
|
+
"test/shoulda_macros/role.rb",
|
64
77
|
"test/shoulda_macros/serialization.rb",
|
65
78
|
"test/test_helper.rb",
|
66
79
|
"test/unit/property/attribute_test.rb",
|
67
|
-
"test/unit/property/
|
80
|
+
"test/unit/property/base_test.rb",
|
68
81
|
"test/unit/property/declaration_test.rb",
|
69
82
|
"test/unit/property/dirty_test.rb",
|
70
83
|
"test/unit/property/index_complex_test.rb",
|
71
84
|
"test/unit/property/index_custom_test.rb",
|
72
85
|
"test/unit/property/index_foreign_test.rb",
|
73
86
|
"test/unit/property/index_simple_test.rb",
|
87
|
+
"test/unit/property/role_test.rb",
|
88
|
+
"test/unit/property/stored_role_test.rb",
|
74
89
|
"test/unit/property/validation_test.rb",
|
75
90
|
"test/unit/serialization/json_test.rb",
|
76
91
|
"test/unit/serialization/marshal_test.rb",
|
data/test/fixtures.rb
CHANGED
@@ -4,6 +4,9 @@ class Employee < ActiveRecord::Base
|
|
4
4
|
property.string 'first_name', :default => '', :index => true
|
5
5
|
property.string 'last_name', :default => '', :index => true
|
6
6
|
property.float 'age'
|
7
|
+
|
8
|
+
def method_in_parent
|
9
|
+
end
|
7
10
|
end
|
8
11
|
|
9
12
|
class Developer < Employee
|
@@ -78,6 +81,23 @@ begin
|
|
78
81
|
t.string 'value'
|
79
82
|
end
|
80
83
|
|
84
|
+
# multilingual index strings in employees
|
85
|
+
create_table 'i_ml_string_employees' do |t|
|
86
|
+
t.integer 'employee_id'
|
87
|
+
t.integer 'version_id'
|
88
|
+
t.string 'lang'
|
89
|
+
t.integer 'site_id'
|
90
|
+
t.string 'key'
|
91
|
+
t.string 'value'
|
92
|
+
end
|
93
|
+
|
94
|
+
# index strings in employees
|
95
|
+
create_table 'i_special_employees' do |t|
|
96
|
+
t.integer 'employee_id'
|
97
|
+
t.string 'key'
|
98
|
+
t.string 'value'
|
99
|
+
end
|
100
|
+
|
81
101
|
# index integer in employees
|
82
102
|
create_table 'i_integer_employees' do |t|
|
83
103
|
t.integer 'employee_id'
|
@@ -99,11 +119,29 @@ begin
|
|
99
119
|
t.string 'name'
|
100
120
|
t.string 'other_name'
|
101
121
|
end
|
122
|
+
|
123
|
+
# Database stored role
|
124
|
+
create_table 'roles' do |t|
|
125
|
+
t.integer 'id'
|
126
|
+
t.string 'name'
|
127
|
+
end
|
128
|
+
|
129
|
+
create_table 'columns' do |t|
|
130
|
+
t.integer 'id'
|
131
|
+
t.integer 'role_id'
|
132
|
+
t.string 'name'
|
133
|
+
# Property Type
|
134
|
+
t.string 'ptype'
|
135
|
+
# Indexed (we store an integer so that we can have multiple index types)
|
136
|
+
t.string 'index'
|
137
|
+
end
|
102
138
|
end
|
103
139
|
end
|
104
140
|
|
105
141
|
ActiveRecord::Base.establish_connection(:adapter=>'sqlite3', :database=>':memory:')
|
106
|
-
|
142
|
+
log_path = Pathname(__FILE__).dirname + '../log/test.log'
|
143
|
+
Dir.mkdir(log_path.dirname) unless File.exist?(log_path.dirname)
|
144
|
+
ActiveRecord::Base.logger = Logger.new(File.open(log_path, 'wb'))
|
107
145
|
ActiveRecord::Migration.verbose = false
|
108
146
|
#PropertyMigration.migrate(:down)
|
109
147
|
PropertyMigration.migrate(:up)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module IndexMacros
|
2
|
+
class IndexedStringEmp < ActiveRecord::Base
|
3
|
+
set_table_name :i_string_employees
|
4
|
+
end
|
5
|
+
|
6
|
+
class MLIndexedStringEmp < ActiveRecord::Base
|
7
|
+
set_table_name :i_ml_string_employees
|
8
|
+
end
|
9
|
+
|
10
|
+
class IndexedIntegerEmp < ActiveRecord::Base
|
11
|
+
set_table_name :i_integer_employees
|
12
|
+
end
|
13
|
+
|
14
|
+
# Simple class
|
15
|
+
class Employee < ActiveRecord::Base
|
16
|
+
include Property
|
17
|
+
|
18
|
+
def index_reader(group_name)
|
19
|
+
if group_name.to_s == 'ml_string'
|
20
|
+
super.merge(:with => {'lang' => ['en', 'fr'], 'site_id' => '123'})
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Test::Unit::TestCase
|
29
|
+
|
30
|
+
def self.should_maintain_indices
|
31
|
+
|
32
|
+
context "assigned to an instance of Dummy" do
|
33
|
+
subject do
|
34
|
+
dummy = IndexMacros::Employee.new
|
35
|
+
dummy.has_role @poet
|
36
|
+
dummy
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'use index_reader method' do
|
40
|
+
assert_equal Hash[:with=>{'lang'=>['en', 'fr'], 'site_id'=>'123'}, "employee_id"=>nil], subject.index_reader(:ml_string)
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'create multilingual string indices on save' do
|
44
|
+
assert_difference('IndexMacros::MLIndexedStringEmp.count', 2) do
|
45
|
+
subject.poem = 'Hyperions Schicksalslied'
|
46
|
+
subject.save
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
should 'create integer indices on save' do
|
51
|
+
assert_difference('IndexMacros::IndexedIntegerEmp.count', 1) do
|
52
|
+
subject.year = 1770
|
53
|
+
subject.save
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'not create blank indices on save' do
|
58
|
+
assert_difference('IndexMacros::IndexedStringEmp.count', 0) do
|
59
|
+
assert_difference('IndexMacros::IndexedIntegerEmp.count', 0) do
|
60
|
+
subject.save
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end # An instance of Person
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.should_not_maintain_indices
|
68
|
+
|
69
|
+
context "assigned to an instance of Dummy" do
|
70
|
+
subject do
|
71
|
+
dummy = IndexMacros::Employee.new
|
72
|
+
dummy.has_role @poet
|
73
|
+
dummy
|
74
|
+
end
|
75
|
+
|
76
|
+
should 'not create indices on save' do
|
77
|
+
assert_difference('IndexMacros::IndexedStringEmp.count', 0) do
|
78
|
+
assert_difference('IndexMacros::IndexedIntegerEmp.count', 0) do
|
79
|
+
subject.year = 1770
|
80
|
+
subject.poem = 'Hyperions Schicksalslied'
|
81
|
+
subject.save
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
should 'not create blank indices on save' do
|
87
|
+
assert_difference('IndexMacros::IndexedStringEmp.count', 0) do
|
88
|
+
assert_difference('IndexMacros::IndexedIntegerEmp.count', 0) do
|
89
|
+
subject.save
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end # An instance of Person
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
class Test::Unit::TestCase
|
2
|
+
def self.should_store_property_definitions(klass)
|
3
|
+
subject { klass.new('Foobar') }
|
4
|
+
|
5
|
+
should 'allow string columns' do
|
6
|
+
subject.property.string('weapon')
|
7
|
+
column = subject.columns['weapon']
|
8
|
+
assert_equal 'weapon', column.name
|
9
|
+
assert_equal String, column.klass
|
10
|
+
assert_equal :string, column.type
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'treat symbol keys as strings' do
|
14
|
+
subject.property.string(:weapon)
|
15
|
+
column = subject.columns['weapon']
|
16
|
+
assert_equal 'weapon', column.name
|
17
|
+
assert_equal String, column.klass
|
18
|
+
assert_equal :string, column.type
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'allow integer columns' do
|
22
|
+
subject.property.integer('indestructible')
|
23
|
+
column = subject.columns['indestructible']
|
24
|
+
assert_equal 'indestructible', column.name
|
25
|
+
assert_equal Fixnum, column.klass
|
26
|
+
assert_equal :integer, column.type
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'allow float columns' do
|
30
|
+
subject.property.float('boat')
|
31
|
+
column = subject.columns['boat']
|
32
|
+
assert_equal 'boat', column.name
|
33
|
+
assert_equal Float, column.klass
|
34
|
+
assert_equal :float, column.type
|
35
|
+
end
|
36
|
+
|
37
|
+
should 'allow datetime columns' do
|
38
|
+
subject.property.datetime('time_weapon')
|
39
|
+
column = subject.columns['time_weapon']
|
40
|
+
assert_equal 'time_weapon', column.name
|
41
|
+
assert_equal Time, column.klass
|
42
|
+
assert_equal :datetime, column.type
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'allow default value option' do
|
46
|
+
subject.property.integer('force', :default => 10)
|
47
|
+
column = subject.columns['force']
|
48
|
+
assert_equal 10, column.default
|
49
|
+
end
|
50
|
+
|
51
|
+
should 'allow index option' do
|
52
|
+
subject.property.string('rolodex', :index => true)
|
53
|
+
column = subject.columns['rolodex']
|
54
|
+
assert column.indexed?
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'return a list of indices on indices' do
|
58
|
+
subject.property.string('rolodex', :index => true)
|
59
|
+
subject.property.integer('foobar', :index => true)
|
60
|
+
assert_equal %w{integer string}, subject.indices.map {|i| i[0].to_s }.sort
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'created with a Hash' do
|
64
|
+
subject { klass.new(:name => 'Foobar') }
|
65
|
+
|
66
|
+
should 'set name' do
|
67
|
+
assert_equal 'Foobar', subject.name
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'created with a String Hash' do
|
72
|
+
subject { klass.new('name' => 'Foobar') }
|
73
|
+
|
74
|
+
should 'set name' do
|
75
|
+
assert_equal 'Foobar', subject.name
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end # should_store_property_definitions
|
79
|
+
|
80
|
+
def self.should_insert_properties_on_has_role_poet
|
81
|
+
context 'added' do
|
82
|
+
|
83
|
+
context 'to a parent class' do
|
84
|
+
setup do
|
85
|
+
@parent = Class.new(ActiveRecord::Base) do
|
86
|
+
set_table_name :dummies
|
87
|
+
include Property
|
88
|
+
property.string 'name'
|
89
|
+
end
|
90
|
+
|
91
|
+
@klass = Class.new(@parent)
|
92
|
+
end
|
93
|
+
|
94
|
+
should 'propagate definitions to child' do
|
95
|
+
@parent.has_role @poet
|
96
|
+
assert_equal %w{name poem year}, @klass.schema.column_names.sort
|
97
|
+
end
|
98
|
+
|
99
|
+
should 'return true on has_role?' do
|
100
|
+
@parent.has_role @poet
|
101
|
+
assert @klass.has_role?(@poet)
|
102
|
+
end
|
103
|
+
|
104
|
+
should 'raise an exception if class contains same definitions' do
|
105
|
+
@parent.property.string 'poem'
|
106
|
+
assert_raise(Property::RedefinedPropertyError) { @parent.has_role @poet }
|
107
|
+
end
|
108
|
+
|
109
|
+
should 'not raise an exception on double inclusion' do
|
110
|
+
@parent.has_role @poet
|
111
|
+
assert_nothing_raised { @parent.has_role @poet }
|
112
|
+
end
|
113
|
+
|
114
|
+
should 'add accessor methods to child' do
|
115
|
+
subject = @klass.new
|
116
|
+
assert_raises(NoMethodError) { subject.poem = 'Poe'}
|
117
|
+
@parent.has_role @poet
|
118
|
+
|
119
|
+
assert_nothing_raised { subject.poem = 'Poe'}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'to a class' do
|
124
|
+
setup do
|
125
|
+
@klass = Class.new(ActiveRecord::Base) do
|
126
|
+
set_table_name :dummies
|
127
|
+
include Property
|
128
|
+
property.string 'name'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
should 'insert definitions' do
|
133
|
+
@klass.has_role @poet
|
134
|
+
assert_equal %w{name poem year}, @klass.schema.column_names.sort
|
135
|
+
end
|
136
|
+
|
137
|
+
should 'return true on class has_role?' do
|
138
|
+
@klass.has_role @poet
|
139
|
+
assert @klass.has_role?(@poet)
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'to an instance' do
|
145
|
+
subject { Developer.new }
|
146
|
+
|
147
|
+
setup do
|
148
|
+
subject.has_role @poet
|
149
|
+
end
|
150
|
+
|
151
|
+
should 'merge property definitions' do
|
152
|
+
assert_equal %w{age first_name language last_name poem year}, subject.schema.column_names.sort
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end # should_insert_properties_on_has_role
|
157
|
+
|
158
|
+
def self.should_add_role_methods
|
159
|
+
context 'added' do
|
160
|
+
context 'to a parent class' do
|
161
|
+
setup do
|
162
|
+
@parent = Class.new(ActiveRecord::Base) do
|
163
|
+
set_table_name :dummies
|
164
|
+
include Property
|
165
|
+
property.string 'name'
|
166
|
+
end
|
167
|
+
|
168
|
+
@klass = Class.new(@parent)
|
169
|
+
end
|
170
|
+
|
171
|
+
should 'add role methods to child' do
|
172
|
+
subject = @klass.new
|
173
|
+
assert_raises(NoMethodError) { subject.muse }
|
174
|
+
@parent.has_role @poet
|
175
|
+
|
176
|
+
assert_nothing_raised { subject.muse }
|
177
|
+
end
|
178
|
+
|
179
|
+
should 'use role methods for defaults' do
|
180
|
+
subject = @klass.new
|
181
|
+
@parent.has_role @poet
|
182
|
+
assert subject.save
|
183
|
+
assert_equal 'I am your muse', subject.poem
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end # should_add_role_methods
|
188
|
+
|
189
|
+
def self.should_take_part_in_used_list(has_defaults = true)
|
190
|
+
|
191
|
+
context 'added' do
|
192
|
+
context 'to a class' do
|
193
|
+
setup do
|
194
|
+
@klass = Class.new(ActiveRecord::Base) do
|
195
|
+
set_table_name :dummies
|
196
|
+
include Property
|
197
|
+
property.string 'name'
|
198
|
+
end
|
199
|
+
|
200
|
+
@klass.has_role @poet
|
201
|
+
end
|
202
|
+
|
203
|
+
subject do
|
204
|
+
@klass.new
|
205
|
+
end
|
206
|
+
|
207
|
+
should 'return true on instance has_role?' do
|
208
|
+
assert subject.has_role?(@poet)
|
209
|
+
end
|
210
|
+
|
211
|
+
should 'not return role without corresponding attributes' do
|
212
|
+
subject.attributes = {'name' => 'hello'}
|
213
|
+
assert_equal [@klass.schema.role], subject.used_roles
|
214
|
+
end
|
215
|
+
|
216
|
+
should 'return role with corresponding attributes' do
|
217
|
+
subject.attributes = {'poem' => 'hello'}
|
218
|
+
roles = @poet.kind_of?(Class) ? @poet.schema.roles : [@poet]
|
219
|
+
assert_equal roles, subject.used_roles
|
220
|
+
end
|
221
|
+
|
222
|
+
should 'not return role only with blank attributes' do
|
223
|
+
subject.attributes = {'name' => ''}
|
224
|
+
assert_equal [], subject.used_roles
|
225
|
+
end
|
226
|
+
|
227
|
+
if has_defaults
|
228
|
+
should 'return role with default attributes after validate' do
|
229
|
+
subject.valid?
|
230
|
+
roles = @poet.kind_of?(Class) ? @poet.schema.roles : [@poet]
|
231
|
+
assert_equal roles, subject.used_roles
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end # to a class
|
235
|
+
end # added
|
236
|
+
end
|
237
|
+
end
|