metaruby 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/History.txt +1 -0
  4. data/Manifest.txt +40 -0
  5. data/README.md +318 -0
  6. data/Rakefile +39 -0
  7. data/lib/metaruby/class.rb +120 -0
  8. data/lib/metaruby/dsls/doc.rb +78 -0
  9. data/lib/metaruby/dsls/find_through_method_missing.rb +76 -0
  10. data/lib/metaruby/dsls.rb +2 -0
  11. data/lib/metaruby/gui/exception_view.rb +124 -0
  12. data/lib/metaruby/gui/html/button.rb +65 -0
  13. data/lib/metaruby/gui/html/collection.rb +103 -0
  14. data/lib/metaruby/gui/html/exception_view.css +8 -0
  15. data/lib/metaruby/gui/html/jquery.min.js +154 -0
  16. data/lib/metaruby/gui/html/jquery.selectfilter.js +65 -0
  17. data/lib/metaruby/gui/html/jquery.tagcloud.min.js +8 -0
  18. data/lib/metaruby/gui/html/jquery.tinysort.min.js +8 -0
  19. data/lib/metaruby/gui/html/list.rhtml +24 -0
  20. data/lib/metaruby/gui/html/page.css +55 -0
  21. data/lib/metaruby/gui/html/page.rb +283 -0
  22. data/lib/metaruby/gui/html/page.rhtml +13 -0
  23. data/lib/metaruby/gui/html/page_body.rhtml +17 -0
  24. data/lib/metaruby/gui/html/rock-website.css +694 -0
  25. data/lib/metaruby/gui/html.rb +16 -0
  26. data/lib/metaruby/gui/model_browser.rb +262 -0
  27. data/lib/metaruby/gui/model_selector.rb +266 -0
  28. data/lib/metaruby/gui/rendering_manager.rb +112 -0
  29. data/lib/metaruby/gui/ruby_constants_item_model.rb +253 -0
  30. data/lib/metaruby/gui.rb +9 -0
  31. data/lib/metaruby/inherited_attribute.rb +482 -0
  32. data/lib/metaruby/module.rb +158 -0
  33. data/lib/metaruby/registration.rb +157 -0
  34. data/lib/metaruby/test.rb +79 -0
  35. data/lib/metaruby.rb +17 -0
  36. data/manifest.xml +12 -0
  37. data/test/suite.rb +15 -0
  38. data/test/test_attributes.rb +323 -0
  39. data/test/test_class.rb +68 -0
  40. data/test/test_dsls.rb +49 -0
  41. data/test/test_module.rb +105 -0
  42. data/test/test_registration.rb +182 -0
  43. metadata +160 -0
@@ -0,0 +1,157 @@
1
+ require 'facets/module/spacename'
2
+ require 'facets/module/basename'
3
+ require 'facets/kernel/call_stack'
4
+ require 'utilrb/object/attribute'
5
+ require 'utilrb/module/attr_predicate'
6
+ module MetaRuby
7
+ # Handling of registration of model hierarchies
8
+ #
9
+ # It depends on the mixed-in object to provide a #supermodel method that
10
+ # returns the model that is parent of +self+
11
+ module Registration
12
+ # The place where this model got defined in the source code
13
+ # The tuple is (file,lineno,method), and can be obtained with
14
+ # facet's #call_stack
15
+ # @return [Array<(String,Integer,Symbol)>]
16
+ attr_accessor :definition_location
17
+
18
+ # Tells {#clear_submodels} whether this model should be removed from
19
+ # the model set or not. The default is false (it should be removed)
20
+ #
21
+ # @return [Boolean]
22
+ attr_predicate :permanent_model?, true
23
+
24
+ # [Set] the set of models that are children of this one
25
+ attribute(:submodels) { Set.new }
26
+
27
+ # Returns the model that is parent of this one
28
+ #
29
+ # The default implementation returns superclass if it is extended by
30
+ # this Registration module, and nil otherwise
31
+ def supermodel
32
+ if superclass.respond_to?(:register_submodel)
33
+ superclass
34
+ end
35
+ end
36
+
37
+ # @return [Boolean] true if the definition context (module, class) in
38
+ # which self is registered is permanent or not w.r.t. the model
39
+ # registration functionality of metaruby
40
+ def permanent_definition_context?
41
+ return false if !name
42
+ definition_context_name = spacename
43
+ if !definition_context_name.empty?
44
+ begin
45
+ enclosing_context = constant("::#{definition_context_name}")
46
+ return !enclosing_context.respond_to?(:permanent_model?) || enclosing_context.permanent_model?
47
+ rescue NameError
48
+ false
49
+ end
50
+ else
51
+ true
52
+ end
53
+ end
54
+
55
+ # @return [Boolean] true if the given object can be accessed by resolving its
56
+ # name as a constant
57
+ def self.accessible_by_name?(object)
58
+ return false if !object.respond_to?(:name) || !object.name
59
+ begin
60
+ constant("::#{object.name}") == object
61
+ rescue NameError
62
+ false
63
+ end
64
+ end
65
+
66
+ # @return [Boolean] true if this object can be accessed by resolving its
67
+ # name as a constant
68
+ def accessible_by_name?
69
+ Registration.accessible_by_name?(self)
70
+ end
71
+
72
+ # Call to register a model that is a submodel of +self+
73
+ def register_submodel(klass)
74
+ if !klass.definition_location
75
+ klass.definition_location = call_stack
76
+ end
77
+
78
+ submodels << klass
79
+ if m = supermodel
80
+ m.register_submodel(klass)
81
+ end
82
+ end
83
+
84
+ # Enumerates all models that are submodels of this class
85
+ def each_submodel
86
+ return enum_for(:each_submodel) if !block_given?
87
+ submodels.each do |obj|
88
+ yield(obj)
89
+ end
90
+ end
91
+
92
+ def clear_model
93
+ if !permanent_model?
94
+ if m = supermodel
95
+ m.deregister_submodels([self])
96
+ end
97
+ if Registration.accessible_by_name?(self)
98
+ Registration.deregister_constant(self)
99
+ end
100
+ end
101
+ clear_submodels
102
+ end
103
+
104
+ # Removes the constant that stores the given object in the Ruby constant
105
+ # hierarchy
106
+ #
107
+ # It assumes that calling #name on the object returns the place in the
108
+ # constant hierarchy where it is stored
109
+ def self.deregister_constant(obj)
110
+ constant("::#{obj.spacename}").send(:remove_const, obj.basename)
111
+ end
112
+
113
+ # Clears all registered submodels
114
+ def clear_submodels
115
+ children = self.submodels.find_all { |m| !m.permanent_model? }
116
+ if !children.empty?
117
+ deregister_submodels(children)
118
+ end
119
+
120
+ children.each do |m|
121
+ # Deregister non-permanent models that are registered in the
122
+ # constant hierarchy
123
+ if Registration.accessible_by_name?(m)
124
+ Registration.deregister_constant(m)
125
+ end
126
+ end
127
+
128
+ # This contains the permanent submodels
129
+ #
130
+ # We can call #clear_submodels while iterating here as it is a
131
+ # constraint that all models in #submodels are permanent (and
132
+ # will therefore not be removed)
133
+ submodels.each { |m| m.clear_submodels }
134
+ # And this the non-permanent ones
135
+ children.each { |m| m.clear_submodels }
136
+ true
137
+ end
138
+
139
+ # Deregisters a set of submodels on this model and all its
140
+ # supermodels
141
+ #
142
+ # This is usually not called directly. Use #clear_submodels instead
143
+ #
144
+ # @param [Set] set the set of submodels to remove
145
+ def deregister_submodels(set)
146
+ current_size = submodels.size
147
+ submodels.subtract(set)
148
+ if m = supermodel
149
+ m.deregister_submodels(set)
150
+ end
151
+ current_size != submodels.size
152
+ end
153
+ end
154
+ end
155
+
156
+
157
+
@@ -0,0 +1,79 @@
1
+ # simplecov must be loaded FIRST. Only the files required after it gets loaded
2
+ # will be profiled !!!
3
+ if ENV['TEST_ENABLE_COVERAGE'] == '1'
4
+ begin
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+ rescue LoadError
8
+ require 'metaruby'
9
+ MetaRuby.warn "coverage is disabled because the 'simplecov' gem cannot be loaded"
10
+ rescue Exception => e
11
+ require 'metaruby'
12
+ MetaRuby.warn "coverage is disabled: #{e.message}"
13
+ end
14
+ end
15
+
16
+ require 'metaruby'
17
+ require 'minitest/autorun'
18
+ require 'minitest/spec'
19
+ require 'flexmock/test_unit'
20
+
21
+ if ENV['TEST_ENABLE_PRY'] != '0'
22
+ begin
23
+ require 'pry'
24
+ if ENV['TEST_DEBUG'] == '1'
25
+ require 'pry-rescue/minitest'
26
+ end
27
+ rescue Exception
28
+ MetaRuby.warn "debugging is disabled because the 'pry' gem cannot be loaded"
29
+ end
30
+ end
31
+
32
+ module MetaRuby
33
+ # This module is the common setup for all tests
34
+ #
35
+ # It should be included in the toplevel describe blocks
36
+ #
37
+ # @example
38
+ # require 'metaruby/test'
39
+ # describe MetaRuby do
40
+ # include MetaRuby::SelfTest
41
+ # end
42
+ #
43
+ module SelfTest
44
+ if defined? FlexMock
45
+ include FlexMock::ArgumentTypes
46
+ include FlexMock::MockContainer
47
+ end
48
+
49
+ def setup
50
+ # Setup code for all the tests
51
+ end
52
+
53
+ def teardown
54
+ if defined? FlexMock
55
+ flexmock_teardown
56
+ end
57
+ # Teardown code for all the tests
58
+ end
59
+ end
60
+ end
61
+
62
+ # Workaround a problem with flexmock and minitest not being compatible with each
63
+ # other (currently). See github.com/jimweirich/flexmock/issues/15.
64
+ if defined?(FlexMock) && !FlexMock::TestUnitFrameworkAdapter.method_defined?(:assertions)
65
+ class FlexMock::TestUnitFrameworkAdapter
66
+ attr_accessor :assertions
67
+ end
68
+ FlexMock.framework_adapter.assertions = 0
69
+ end
70
+
71
+ module Minitest
72
+ class Spec
73
+ include MetaRuby::SelfTest
74
+ end
75
+ class Test
76
+ include MetaRuby::SelfTest
77
+ end
78
+ end
79
+
data/lib/metaruby.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'utilrb/object/attribute'
2
+
3
+ require 'metaruby/inherited_attribute'
4
+ require 'metaruby/registration'
5
+ require 'metaruby/module'
6
+ require 'metaruby/class'
7
+
8
+ # The toplevel namespace for MetaRuby
9
+ #
10
+ # MetaRuby is an implementation of a (very small) modelling toolkit that uses
11
+ # the Ruby type system as its meta-metamodel
12
+ require 'utilrb/logger'
13
+ module MetaRuby
14
+ LIB_DIR = File.expand_path('metaruby', File.dirname(__FILE__))
15
+ extend Logger::Root('MetaRuby', Logger::WARN)
16
+ end
17
+
data/manifest.xml ADDED
@@ -0,0 +1,12 @@
1
+ <package>
2
+ <description brief="Modelling using the Ruby language as a metamodel">
3
+ </description>
4
+ <maintainer>Sylvain Joyeux/sylvain.joyeux@m4x.org</maintainer>
5
+ <license>LGPLv3</license>
6
+
7
+ <depend package="utilrb" />
8
+ <depend package="kramdown" optional="1" />
9
+
10
+ <test_depend package="minitest" />
11
+ <test_depend package="flexmock" />
12
+ </package>
data/test/suite.rb ADDED
@@ -0,0 +1,15 @@
1
+ # Coverage is enabled by default when running the whole suite
2
+ ENV['TEST_ENABLE_COVERAGE'] ||= '1'
3
+
4
+ # Require all your test files here. Always prepend ./ and use the relative path
5
+ # to the Ruby library root
6
+ require 'metaruby/test'
7
+ require './test/test_class'
8
+ require './test/test_module'
9
+ require './test/test_attributes'
10
+ require './test/test_registration'
11
+ require './test/test_dsls'
12
+
13
+ # Put the root logger to DEBUG so that all debug blocks are executed
14
+ MetaRuby.logger = Logger.new(File.open("/dev/null", 'w'))
15
+ MetaRuby.logger.level = Logger::DEBUG
@@ -0,0 +1,323 @@
1
+ require 'metaruby/test'
2
+
3
+ class TC_Models < MiniTest::Test
4
+ def test_inherited_attribute_class
5
+ a = Class.new do
6
+ class << self
7
+ extend MetaRuby::Attributes
8
+ inherited_attribute(:signature, :signatures) { Array.new }
9
+ inherited_attribute(:mapped, :map, :map => true) { Hash.new }
10
+ end
11
+ end
12
+ b = Class.new(a) do
13
+ include Module.new # include an empty module between a and b to check that the module
14
+ # is skipped transparently
15
+ singleton_class.inherited_attribute(:child_attribute) { Array.new }
16
+ end
17
+ check_inherited_attribute(a, b)
18
+
19
+ # Test for singleton class support
20
+ object = b.new
21
+ assert(object.singleton_class.respond_to?(:signatures))
22
+ object.singleton_class.signatures << :in_singleton
23
+ assert_equal([:in_singleton], object.singleton_class.signatures)
24
+ end
25
+
26
+ def check_inherited_attribute(base, derived)
27
+ assert(base.respond_to?(:each_signature))
28
+ assert(base.respond_to?(:signatures))
29
+ assert(!base.respond_to?(:has_signature?))
30
+ assert(!base.respond_to?(:find_signatures))
31
+
32
+ assert(base.respond_to?(:each_mapped))
33
+ assert(base.respond_to?(:map))
34
+ assert(base.respond_to?(:has_mapped?))
35
+
36
+ base.signatures << :in_base
37
+ base.map[:base] = 10
38
+ base.map[:overriden] = 20
39
+ assert_equal([:in_base], base.enum_for(:each_signature).to_a)
40
+ assert_equal([10].to_set, base.enum_for(:each_mapped, :base, false).to_set)
41
+
42
+ assert(!base.respond_to?(:child_attribute))
43
+ assert(!base.respond_to?(:each_child_attribute))
44
+ assert(derived.respond_to?(:child_attribute))
45
+ assert(derived.respond_to?(:each_child_attribute))
46
+
47
+ derived.signatures << :in_derived
48
+
49
+ derived.map[:overriden] = 15
50
+ derived.map[:derived] = 25
51
+
52
+ assert_equal([:in_derived, :in_base], derived.enum_for(:each_signature).to_a)
53
+ assert_equal([20, 15].to_set, derived.enum_for(:each_mapped, :overriden, false).to_set)
54
+ assert_equal([15].to_set, derived.enum_for(:each_mapped, :overriden, true).to_set)
55
+ assert_equal([25].to_set, derived.enum_for(:each_mapped, :derived).to_set)
56
+ assert_equal([[:base, 10], [:overriden, 20], [:overriden, 15], [:derived, 25]].to_set, derived.enum_for(:each_mapped, nil, false).to_set)
57
+ assert_equal([[:base, 10], [:overriden, 15], [:derived, 25]].to_set, derived.enum_for(:each_mapped, nil, true).to_set)
58
+ end
59
+
60
+ def test_inherited_attribute_non_mapping_promote
61
+ a = Class.new do
62
+ class << self
63
+ extend MetaRuby::Attributes
64
+ def promote_value(v)
65
+ v
66
+ end
67
+ inherited_attribute(:value, :values) { Array.new }
68
+ end
69
+ end
70
+ b = flexmock(Class.new(a), 'b')
71
+ c = flexmock(Class.new(b), 'c')
72
+ d = flexmock(Class.new(c), 'd')
73
+
74
+ c.should_receive(:promote_value).with(10).and_return("10_b_c").once.ordered
75
+ d.should_receive(:promote_value).with("10_b_c").and_return(12).once.ordered
76
+ c.should_receive(:promote_value).with(11).and_return("11_b_c").once.ordered
77
+ d.should_receive(:promote_value).with("11_b_c").and_return(13).once.ordered
78
+ b.should_receive(:promote_value).with(0).and_return("0_b_c").once.ordered
79
+ c.should_receive(:promote_value).with("0_b_c").and_return("0_c_d").once.ordered
80
+ d.should_receive(:promote_value).with("0_c_d").and_return(2).once.ordered
81
+ b.should_receive(:promote_value).with(1).and_return("1_b_c").once.ordered
82
+ c.should_receive(:promote_value).with("1_b_c").and_return("1_c_d").once.ordered
83
+ d.should_receive(:promote_value).with("1_c_d").and_return(3).once.ordered
84
+
85
+ a.values << 0 << 1
86
+ b.values << 10 << 11
87
+ # Do NOT add anything at the level of C. Its promote_value method should
88
+ # still be called, though
89
+ d.values << 100 << 110
90
+ assert_equal [0, 1], a.each_value.to_a
91
+ assert_equal [100, 110, 12, 13, 2, 3], d.each_value.to_a
92
+ end
93
+
94
+ def test_inherited_attribute_mapping_promote
95
+ a = Class.new do
96
+ class << self
97
+ extend MetaRuby::Attributes
98
+ def promote_value(key, v)
99
+ end
100
+ def name; 'A' end
101
+ inherited_attribute(:value, :values, :map => true) { Hash.new }
102
+ end
103
+ end
104
+ b = Class.new(a)
105
+ c = Class.new(b)
106
+ d = Class.new(c)
107
+
108
+ flexmock(c).should_receive(:promote_value).with('b', 2).and_return("b2_b_c").once.ordered
109
+ flexmock(d).should_receive(:promote_value).with('b', "b2_b_c").and_return(15).once.ordered
110
+
111
+ flexmock(c).should_receive(:promote_value).with('c', 3).and_return("c3_b_c").once.ordered
112
+ flexmock(d).should_receive(:promote_value).with('c', "c3_b_c").and_return(16).once.ordered
113
+
114
+ flexmock(b).should_receive(:promote_value).with('a', 0).and_return("a0_a_b").once.ordered
115
+ flexmock(c).should_receive(:promote_value).with('a', "a0_a_b").and_return("a0_b_c").once.ordered
116
+ flexmock(d).should_receive(:promote_value).with('a', "a0_b_c").and_return(10).once.ordered
117
+
118
+ a.values.merge!('a' => 0, 'b' => 1)
119
+ b.values.merge!('b' => 2, 'c' => 3, 'd' => 4)
120
+ d.values.merge!('d' => 5, 'e' => 6)
121
+ assert_equal [['d', 5], ['e', 6], ['b', 15], ['c', 16], ['a', 10]], d.each_value.to_a
122
+ end
123
+
124
+ def test_inherited_attribute_mapping_promote_non_uniq
125
+ a = Class.new do
126
+ class << self
127
+ extend MetaRuby::Attributes
128
+ def promote_value(key, v)
129
+ end
130
+ inherited_attribute(:value, :values, :map => true) { Hash.new }
131
+ end
132
+ end
133
+ b = flexmock(Class.new(a), 'b')
134
+ c = flexmock(Class.new(b), 'c')
135
+ d = flexmock(Class.new(c), 'd')
136
+
137
+ c.should_receive(:promote_value).with('b', 2).and_return("b2_b_c").once.ordered
138
+ d.should_receive(:promote_value).with('b', "b2_b_c").and_return(12).once.ordered
139
+
140
+ c.should_receive(:promote_value).with('c', 3).and_return("c3_b_c").once.ordered
141
+ d.should_receive(:promote_value).with('c', "c3_b_c").and_return(13).once.ordered
142
+
143
+ c.should_receive(:promote_value).with('d', 4).and_return("d4_b_c").once.ordered
144
+ d.should_receive(:promote_value).with('d', "d4_b_c").and_return(14).once.ordered
145
+
146
+ b.should_receive(:promote_value).with('a', 0).and_return("a0_a_b").once.ordered
147
+ c.should_receive(:promote_value).with('a', "a0_a_b").and_return("a0_b_c").once.ordered
148
+ d.should_receive(:promote_value).with('a', "a0_b_c").and_return(10).once.ordered
149
+
150
+ b.should_receive(:promote_value).with('b', 1).and_return("b1_a_b").once.ordered
151
+ c.should_receive(:promote_value).with('b', "b1_a_b").and_return("b1_b_c").once.ordered
152
+ d.should_receive(:promote_value).with('b', "b1_b_c").and_return(11).once.ordered
153
+
154
+ a.values.merge!('a' => 0, 'b' => 1)
155
+ b.values.merge!('b' => 2, 'c' => 3, 'd' => 4)
156
+ d.values.merge!('d' => 5, 'e' => 6)
157
+ assert_equal [['d', 5], ['e', 6], ['b', 12], ['c', 13], ['d', 14], ['a', 10], ['b', 11]], d.each_value(nil, false).to_a
158
+ end
159
+
160
+ def test_inherited_attribute_mapping_promote_with_key_uniq
161
+ a = Class.new do
162
+ class << self
163
+ extend MetaRuby::Attributes
164
+ def promote_value(key, v)
165
+ end
166
+ inherited_attribute(:value, :values, :map => true) { Hash.new }
167
+ end
168
+ end
169
+ b = flexmock(Class.new(a), 'b')
170
+ c = flexmock(Class.new(b), 'c')
171
+ d = flexmock(Class.new(c), 'd')
172
+
173
+ c.should_receive(:promote_value).with('b', 2).and_return("b2_b_c").once.ordered
174
+ d.should_receive(:promote_value).with('b', "b2_b_c").and_return(12).once.ordered
175
+
176
+ a.values.merge!('a' => 0, 'b' => 1)
177
+ b.values.merge!('b' => 2, 'c' => 3, 'd' => 4)
178
+ d.values.merge!('d' => 5, 'e' => 6)
179
+ assert_equal [12], d.each_value('b', true).to_a
180
+ end
181
+
182
+ def test_inherited_attribute_mapping_promote_with_key_non_uniq
183
+ a = Class.new do
184
+ class << self
185
+ extend MetaRuby::Attributes
186
+ def promote_value(key, v)
187
+ end
188
+ inherited_attribute(:value, :values, :map => true) { Hash.new }
189
+ end
190
+ end
191
+ b = flexmock(Class.new(a), 'b')
192
+ c = flexmock(Class.new(b), 'c')
193
+ d = flexmock(Class.new(c), 'd')
194
+
195
+ c.should_receive(:promote_value).with('b', 2).and_return("b2_b_c").once.ordered
196
+ d.should_receive(:promote_value).with('b', "b2_b_c").and_return(12).once.ordered
197
+
198
+ b.should_receive(:promote_value).with('b', 1).and_return("b1_a_b").once.ordered
199
+ c.should_receive(:promote_value).with('b', "b1_a_b").and_return("b1_b_c").once.ordered
200
+ d.should_receive(:promote_value).with('b', "b1_b_c").and_return(11).once.ordered
201
+
202
+ a.values.merge!('a' => 0, 'b' => 1)
203
+ b.values.merge!('b' => 2, 'c' => 3, 'd' => 4)
204
+ d.values.merge!('d' => 5, 'e' => 6)
205
+ assert_equal [12, 11], d.each_value('b', false).to_a
206
+ end
207
+ end
208
+
209
+ describe MetaRuby::Attributes do
210
+ describe "#inherited_single_value_attribute" do
211
+ attr_reader :base, :sub, :subsub
212
+ describe "plain" do
213
+ before do
214
+ @base = Class.new do
215
+ class << self
216
+ extend MetaRuby::Attributes
217
+ inherited_single_value_attribute :var
218
+ end
219
+ end
220
+ @sub = Class.new(base)
221
+ @subsub = Class.new(sub)
222
+ end
223
+
224
+ it "should set the value if given an argument" do
225
+ base.var(10)
226
+ assert_equal 10, base.var
227
+ end
228
+ it "should return the value from the parent model if not set" do
229
+ base.var(10)
230
+ assert_equal 10, sub.var
231
+ end
232
+ it "should return nil if the instance variable is explicitly set to nil" do
233
+ base.var 10
234
+ sub.var nil
235
+ assert_equal nil, subsub.var
236
+ end
237
+ end
238
+
239
+ describe "with default" do
240
+ before do
241
+ @base = Class.new do
242
+ class << self
243
+ extend MetaRuby::Attributes
244
+ inherited_single_value_attribute(:var) { 10 }
245
+ end
246
+ end
247
+ @sub = Class.new(base)
248
+ @subsub = Class.new(sub)
249
+ end
250
+
251
+ it "should be accessible at each level" do
252
+ assert_equal 10, base.var
253
+ assert_equal 10, sub.var
254
+ assert_equal 10, subsub.var
255
+ end
256
+
257
+ it "should set only the bottom class" do
258
+ assert_equal 10, base.var
259
+ sub.var(nil)
260
+ assert_equal nil, sub.var
261
+ assert_equal nil, subsub.var
262
+ end
263
+ end
264
+
265
+ describe "with promotion" do
266
+ before do
267
+ @base = Class.new do
268
+ class << self
269
+ extend MetaRuby::Attributes
270
+ def promote_var(value); value * 2 end
271
+ inherited_single_value_attribute(:var)
272
+ end
273
+ end
274
+ @sub = Class.new(base) do
275
+ class << self
276
+ def promote_var(value); value * 4 end
277
+ end
278
+ end
279
+ @subsub = Class.new(sub) do
280
+ class << self
281
+ def promote_var(value); value - 10 end
282
+ end
283
+ end
284
+ end
285
+
286
+ it "should apply the promotion method at each level" do
287
+ base.var(10)
288
+ assert_equal 10, base.var
289
+ assert_equal 40, sub.var
290
+ assert_equal 30, subsub.var
291
+ end
292
+ end
293
+
294
+ describe "with default with promotion" do
295
+ before do
296
+ @base = Class.new do
297
+ class << self
298
+ extend MetaRuby::Attributes
299
+ def promote_var(value); value * 2 end
300
+ inherited_single_value_attribute(:var) { 10 }
301
+ end
302
+ end
303
+ @sub = Class.new(base) do
304
+ class << self
305
+ def promote_var(value); value * 4 end
306
+ end
307
+ end
308
+ @subsub = Class.new(sub) do
309
+ class << self
310
+ def promote_var(value); value - 10 end
311
+ end
312
+ end
313
+ end
314
+
315
+ it "should apply the promotion method at each level" do
316
+ assert_equal 10, base.var
317
+ assert_equal 40, sub.var
318
+ assert_equal 30, subsub.var
319
+ end
320
+ end
321
+ end
322
+ end
323
+
@@ -0,0 +1,68 @@
1
+ require 'metaruby/test'
2
+
3
+ class Base
4
+ extend MetaRuby::ModelAsClass
5
+ end
6
+
7
+ module DefinitionContext
8
+ class Klass < Base; end
9
+ end
10
+
11
+ module PermanentDefinitionContext
12
+ def self.permanent_model?; true end
13
+ class Klass < Base; end
14
+ end
15
+
16
+ module NonPermanentDefinitionContext
17
+ def self.permanent_model?; false end
18
+ class Klass < Base; end
19
+ end
20
+
21
+ describe MetaRuby::ModelAsClass do
22
+ include MetaRuby::SelfTest
23
+
24
+ before do
25
+ # Code that is run before each test
26
+ end
27
+ after do
28
+ # Code that is run after each test
29
+ end
30
+
31
+ describe "Using modules as metamodel" do
32
+ it "should apply the Attribute module on sub-metamodels for classes" do
33
+ mod = Module.new { include MetaRuby::ModelAsClass }
34
+ sub = Module.new { include mod }
35
+ assert mod.respond_to?(:inherited_attribute)
36
+ assert sub.respond_to?(:inherited_attribute)
37
+ end
38
+ end
39
+
40
+ describe "#new_submodel" do
41
+ it "should call setup_submodel only once" do
42
+ mod = Module.new { include MetaRuby::ModelAsClass }
43
+ klass = Class.new { extend mod }
44
+ flexmock(klass).should_receive(:setup_submodel).once
45
+ klass.new_submodel
46
+ end
47
+ it "should set permanent_model to false on the class" do
48
+ end
49
+ end
50
+
51
+ describe "creating subclasses" do
52
+ it "should set permanent_model to false on the class if the enclosing context is not properly registered as a constant" do
53
+ definition_context = Module.new do
54
+ Klass = Class.new(Base)
55
+ end
56
+ assert !definition_context.const_get(:Klass).permanent_model?
57
+ end
58
+ it "should set permanent_model to true on the class if the enclosing context is properly registered as a constant but is not responding to permanent_model?" do
59
+ assert DefinitionContext::Klass.permanent_model?
60
+ end
61
+ it "should set permanent_model to true on the class if the enclosing context is permanent" do
62
+ assert PermanentDefinitionContext::Klass.permanent_model?
63
+ end
64
+ it "should set permanent_model to false on the class if the enclosing context is not permanent" do
65
+ assert !NonPermanentDefinitionContext::Klass.permanent_model?
66
+ end
67
+ end
68
+ end