metaruby 1.0.0.rc2 → 1.0.0.rc3

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,8 +1,44 @@
1
1
  require 'set'
2
2
  require 'utilrb/module/dsl_attribute'
3
3
  module MetaRuby
4
+ # Basic functionality for attributes that are aware of inheritance
5
+ #
6
+ # There's basically two main interfaces: {.inherited_single_value_attribute}
7
+ # and {.inherited_attribute}.
8
+ #
9
+ # The former will return the value as set at the lowest level in the
10
+ # model hierarchy (i.e. on self, then on supermodel if self is unset and so
11
+ # forth).
12
+ #
13
+ # The latter enumerates a collection (e.g. Array, Set or Hash). If a map
14
+ # is used (such as a Hash), additional functionality gives different choices
15
+ # as to how the key-value mapping is handled w.r.t. model hierarchy.
16
+ #
17
+ # In both cases, a value returned by a submodel is optionally passed through
18
+ # a promotion method (called #promote_#attributename) which allows to update
19
+ # the returned value (as e.g. update a possible back-reference of the
20
+ # enumerated value to its containing model from the original model to the
21
+ # receiver).
22
+ #
23
+ # @example promotion to update back references
24
+ # class Port; attr_accessor :component_model end
25
+ # class Component
26
+ # inherited_attribute(:ports, :port, map: true) { Hash.new }
27
+ #
28
+ # # Update #component_model to make it point to the receiver instead
29
+ # # of the original model. Note that metaruby does not memoize the
30
+ # # result, so it has to be done in the promote method if it is
31
+ # # desired
32
+ # def promote_port(port)
33
+ # port = port.dup
34
+ # port.component_model = self
35
+ # port
36
+ # end
37
+ # end
4
38
  module Attributes
5
- InheritedAttribute = Struct.new :single_value, :name, :accessor_name, :init
39
+ # Internal representation of inherited attributes
40
+ class InheritedAttribute < Struct.new(:single_value, :name, :accessor_name, :init)
41
+ end
6
42
 
7
43
  # The set of inherited attributes defined on this object
8
44
  # @return [Array<InheritedAttribute>]
@@ -35,6 +71,9 @@ module MetaRuby
35
71
 
36
72
  # Defines an attribute that holds at most a single value
37
73
  #
74
+ # The value returned by the defined accessor will be the one set at the
75
+ # lowest level in the model hierarchy (i.e. self, then superclass, ...)
76
+ #
38
77
  # @param [String] name the attribute name
39
78
  # @return [InheritedAttribute] the attribute definition
40
79
  # @raise [ArgumentError] if no attribute with that name exists
@@ -62,6 +101,8 @@ module MetaRuby
62
101
  nil
63
102
  end
64
103
 
104
+ # @api private
105
+ #
65
106
  # Helper method for {#inherited_single_value_attribute} in case there
66
107
  # are no promotion method(s) defined
67
108
  def define_single_value_without_promotion(method_name, ivar)
@@ -99,6 +140,8 @@ module MetaRuby
99
140
  EOF
100
141
  end
101
142
 
143
+ # @api private
144
+ #
102
145
  # Helper method for {#inherited_single_value_attribute} in case there is
103
146
  # a promotion method defined
104
147
  def define_single_value_with_promotion(method_name, promotion_method_name, ivar)
@@ -146,14 +189,14 @@ module MetaRuby
146
189
  # relevant methods and accessors to allow accessing it in a way that
147
190
  # makes sense when embedded in a model hierarchy
148
191
  #
149
- # More specifically, it defines a <tt>each_#{name}(&iterator)</tt>
150
- # instance method and a <tt>each_#{name}(&iterator)</tt>
192
+ # More specifically, it defines a <tt>each_#name(&iterator)</tt>
193
+ # instance method and a <tt>each_#name(&iterator)</tt>
151
194
  # class method which iterates (in order) on
152
- # - the instance #{name} attribute
153
- # - the singleton class #{name} attribute
154
- # - the class #{name} attribute
155
- # - the superclass #{name} attribute
156
- # - the superclass' superclass #{name} attribute
195
+ # - the instance #name attribute
196
+ # - the singleton class #name attribute
197
+ # - the class #name attribute
198
+ # - the superclass #name attribute
199
+ # - the superclass' superclass #name attribute
157
200
  # ...
158
201
  #
159
202
  # This method can be used on modules, in which case the module is used as if
@@ -314,6 +357,8 @@ module MetaRuby
314
357
  end
315
358
  end
316
359
 
360
+ # @api private
361
+ #
317
362
  # Helper class that defines the iteration method for inherited_attribute
318
363
  # when :map is set and there is not promotion method
319
364
  def self.map_without_promotion(name, attribute_name, options)
@@ -364,6 +409,8 @@ module MetaRuby
364
409
  return code, file, line
365
410
  end
366
411
 
412
+ # @api private
413
+ #
367
414
  # Helper class that defines the iteration method for inherited_attribute
368
415
  # when :map is not set and there is no promotion method
369
416
  def self.nomap_without_promotion(name, attribute_name, options)
@@ -388,6 +435,8 @@ module MetaRuby
388
435
  return code, file, line
389
436
  end
390
437
 
438
+ # @api private
439
+ #
391
440
  # Helper class that defines the iteration method for inherited_attribute
392
441
  # when :map is set and there is a promotion method
393
442
  def self.map_with_promotion(name, attribute_name, options)
@@ -453,6 +502,8 @@ module MetaRuby
453
502
  return code, file, line
454
503
  end
455
504
 
505
+ # @api private
506
+ #
456
507
  # Helper class that defines the iteration method for inherited_attribute
457
508
  # when :map is not set and there is a promotion method
458
509
  def self.nomap_with_promotion(name, attribute_name, options)
@@ -24,9 +24,18 @@ module MetaRuby
24
24
  include Registration
25
25
  extend Attributes
26
26
 
27
- # @return [String] set or get the documentation text for this model
27
+ # @!method doc
28
+ # @overload doc
29
+ # @return [String] the documentation text for this model
30
+ # @overload doc(new_doc)
31
+ # @param [String] new_doc the new documentation
32
+ # @return [String] the documentation text for this model
28
33
  inherited_single_value_attribute :doc
29
34
 
35
+ # Validate that a string can be used as a constant name
36
+ #
37
+ # @param [String] name the name to validate
38
+ # @raise [ArgumentError] if the name cannot be used as a constant name
30
39
  def self.validate_constant_name(name)
31
40
  if name !~ /^[A-Z]\w+$/
32
41
  raise ArgumentError, "#{name} is not a valid model name"
@@ -38,6 +47,16 @@ module MetaRuby
38
47
  #
39
48
  # It is usually used to create specific DSL-like methods that allow to
40
49
  # create these models
50
+ #
51
+ # @param [Module,Class] namespace
52
+ # @param [String] name the model name, it must be valid for a Ruby
53
+ # constant name
54
+ # @param [Module] base_model the base model, which should include
55
+ # {ModelAsModule} itself
56
+ # @param [Array] args additional arguments to pass to base_model's
57
+ # #setup_submodel
58
+ # @param [#call] block block passed to base_model's #setup_submodel
59
+ # @return [Module] the new model
41
60
  def self.create_and_register_submodel(namespace, name, base_model, *args, &block)
42
61
  ModelAsModule.validate_constant_name(name)
43
62
 
@@ -68,6 +87,8 @@ module MetaRuby
68
87
  # True if this model is a root model
69
88
  attr_predicate :root?, true
70
89
 
90
+ # @!attribute [rw] name
91
+ #
71
92
  # Sets a name on this model
72
93
  #
73
94
  # Only use this on 'anonymous models', i.e. on models that are not
@@ -83,25 +104,21 @@ module MetaRuby
83
104
  @name = name
84
105
  end
85
106
 
86
- # Set the root model. See {root_model}
107
+ # Set or get the root model
87
108
  attr_accessor :supermodel
88
109
 
89
110
  # Creates a new DataServiceModel that is a submodel of +self+
90
111
  #
91
- # @param [Hash] options the option hash
92
- # @option options [String] :name the submodel name. Use this option
112
+ # @param [String] name the submodel name. Use this option
93
113
  # only for "anonymous" models, i.e. models that won't be
94
114
  # registered on a Ruby constant
95
- # @option options [Class] :type (self.class) the type of the submodel
115
+ # @param [Class] type (self.class) the type of the submodel
96
116
  #
97
- def new_submodel(options = Hash.new, &block)
98
- options, submodel_options = Kernel.filter_options options,
99
- :name => nil, :type => self.class
100
-
101
- model = options[:type].new
117
+ def new_submodel(name: nil, type: self.class, **submodel_options, &block)
118
+ model = type.new
102
119
  model.extend ModelAsModule
103
- if options[:name]
104
- model.name = options[:name].dup
120
+ if name
121
+ model.name = name.dup
105
122
  end
106
123
  model.definition_location = call_stack
107
124
  setup_submodel(model, submodel_options, &block)
@@ -3,6 +3,7 @@ require 'facets/module/basename'
3
3
  require 'facets/kernel/call_stack'
4
4
  require 'utilrb/object/attribute'
5
5
  require 'utilrb/module/attr_predicate'
6
+
6
7
  module MetaRuby
7
8
  # Handling of registration of model hierarchies
8
9
  #
@@ -21,8 +22,10 @@ module MetaRuby
21
22
  # @return [Boolean]
22
23
  attr_predicate :permanent_model?, true
23
24
 
24
- # @return [Set] the set of models that are children of this one
25
- attribute(:submodels) { Set.new }
25
+ # @api private
26
+ #
27
+ # @return [Array<WeakRef>] the set of models that are children of this one
28
+ attribute(:submodels) { Array.new }
26
29
 
27
30
  # Returns the model that is parent of this one
28
31
  #
@@ -34,6 +37,11 @@ module MetaRuby
34
37
  end
35
38
  end
36
39
 
40
+ # Returns whether a model is a submodel of self
41
+ def has_submodel?(model)
42
+ each_submodel.any? { |m| m == model }
43
+ end
44
+
37
45
  # @return [Boolean] true if the definition context (module, class) in
38
46
  # which self is registered is permanent or not w.r.t. the model
39
47
  # registration functionality of metaruby
@@ -75,7 +83,7 @@ module MetaRuby
75
83
  klass.definition_location = call_stack
76
84
  end
77
85
 
78
- submodels << klass
86
+ submodels << WeakRef.new(klass)
79
87
  if m = supermodel
80
88
  m.register_submodel(klass)
81
89
  end
@@ -84,11 +92,23 @@ module MetaRuby
84
92
  # Enumerates all models that are submodels of this class
85
93
  def each_submodel
86
94
  return enum_for(:each_submodel) if !block_given?
87
- submodels.each do |obj|
88
- yield(obj)
95
+ submodels.delete_if do |obj|
96
+ begin
97
+ yield(obj.__getobj__)
98
+ false
99
+ rescue WeakRef::RefError
100
+ true
101
+ end
89
102
  end
90
103
  end
91
104
 
105
+ # Clears this model
106
+ #
107
+ # It deregisters sef if it is not a {#permanent_model?}, and clears the
108
+ # submodels
109
+ #
110
+ # Model classes and modules should also clear their respective
111
+ # attributes (if there are any)
92
112
  def clear_model
93
113
  if !permanent_model?
94
114
  if m = supermodel
@@ -110,9 +130,9 @@ module MetaRuby
110
130
  constant("::#{obj.spacename}").send(:remove_const, obj.basename)
111
131
  end
112
132
 
113
- # Clears all registered submodels
133
+ # Recursively deregisters all non-permanent submodels
114
134
  def clear_submodels
115
- children = self.submodels.find_all { |m| !m.permanent_model? }
135
+ children = each_submodel.find_all { |m| !m.permanent_model? }
116
136
  if !children.empty?
117
137
  deregister_submodels(children)
118
138
  end
@@ -130,25 +150,37 @@ module MetaRuby
130
150
  # We can call #clear_submodels while iterating here as it is a
131
151
  # constraint that all models in #submodels are permanent (and
132
152
  # will therefore not be removed)
133
- submodels.each { |m| m.clear_submodels }
153
+ each_submodel { |m| m.clear_submodels }
134
154
  # And this the non-permanent ones
135
155
  children.each { |m| m.clear_submodels }
136
156
  true
137
157
  end
138
158
 
159
+ # @api private
160
+ #
139
161
  # Deregisters a set of submodels on this model and all its
140
162
  # supermodels
141
163
  #
142
164
  # This is usually not called directly. Use #clear_submodels instead
143
165
  #
144
- # @param [ValueSet] set the set of submodels to remove
166
+ # @param [Set] set the set of submodels to remove
145
167
  def deregister_submodels(set)
146
- current_size = submodels.size
147
- submodels.subtract(set.to_value_set)
168
+ has_match = false
169
+ submodels.delete_if do |m|
170
+ begin
171
+ m = m.__getobj__
172
+ if set.include?(m)
173
+ has_match = true
174
+ end
175
+ rescue WeakRef::RefError
176
+ true
177
+ end
178
+ end
179
+
148
180
  if m = supermodel
149
181
  m.deregister_submodels(set)
150
182
  end
151
- current_size != submodels.size
183
+ has_match
152
184
  end
153
185
  end
154
186
  end
data/lib/metaruby/test.rb CHANGED
@@ -34,30 +34,26 @@ end
34
34
  module MetaRuby
35
35
  # This module is the common setup for all tests
36
36
  #
37
- # It should be included in the toplevel describe blocks
37
+ # It is included in all the minitest tests
38
38
  #
39
39
  # @example
40
40
  # require 'metaruby/test'
41
41
  # describe MetaRuby do
42
- # include MetaRuby::SelfTest
42
+ # # Use helpers methods from SelfTest here
43
43
  # end
44
44
  #
45
45
  module SelfTest
46
+ # Common setup code for all metaruby tests
46
47
  def setup
47
- # Setup code for all the tests
48
48
  end
49
49
 
50
+ # Common teardown code for all metaruby tests
50
51
  def teardown
51
52
  end
52
53
  end
53
54
  end
54
55
 
55
- module Minitest
56
- class Spec
57
- include MetaRuby::SelfTest
58
- end
59
- class Test
60
- include MetaRuby::SelfTest
61
- end
56
+ class Minitest::Test
57
+ include MetaRuby::SelfTest
62
58
  end
63
59
 
@@ -1,3 +1,4 @@
1
1
  module MetaRuby
2
- VERSION = "1.0.0.rc2"
2
+ # The metaruby library version
3
+ VERSION = "1.0.0.rc3"
3
4
  end
data/lib/yard-metaruby.rb CHANGED
@@ -1,14 +1,21 @@
1
1
  require 'pp'
2
2
  module MetaRuby
3
+ # Yard plugin to handle some of the metaruby DSL methods
4
+ #
5
+ # This is used by adding
6
+ #
7
+ # --plugin metaruby
8
+ #
9
+ # to the .yardopts file
3
10
  module YARD
4
11
  include ::YARD
12
+
13
+ # Handling of {Attributes#inherited_attribute}
5
14
  class InheritedAttributeHandler < YARD::Handlers::Ruby::AttributeHandler
6
15
  handles method_call(:inherited_attribute)
7
16
  namespace_only
8
17
 
9
- def self.process(handler, name, attr_name, is_map, key_name = nil, return_type = nil)
10
- end
11
-
18
+ # Callback handled by YARD
12
19
  def process
13
20
  name = statement.parameters[0].jump(:tstring_content, :ident).source
14
21
  if statement.parameters.size == 4
data/manifest.xml CHANGED
@@ -4,6 +4,7 @@
4
4
  <maintainer>Sylvain Joyeux/sylvain.joyeux@m4x.org</maintainer>
5
5
  <license>LGPLv3</license>
6
6
 
7
+ <depend package="bundler" />
7
8
  <depend package="utilrb" />
8
9
  <depend package="kramdown" optional="1" />
9
10
  </package>
data/metaruby.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.extra_rdoc_files = ["README.md"]
19
19
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
20
 
21
- s.add_runtime_dependency "utilrb", ">= 2.1.0.a"
21
+ s.add_runtime_dependency "utilrb", ">= 3.0.0.a"
22
22
  s.add_runtime_dependency "kramdown"
23
23
  s.add_development_dependency "flexmock", ">= 2.0.0"
24
24
  s.add_development_dependency "minitest", ">= 5.0", "~> 5.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metaruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc2
4
+ version: 1.0.0.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-26 00:00:00.000000000 Z
11
+ date: 2015-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: utilrb
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.1.0.a
19
+ version: 3.0.0.a
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 2.1.0.a
26
+ version: 3.0.0.a
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: kramdown
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +106,7 @@ files:
106
106
  - lib/metaruby/dsls/doc.rb
107
107
  - lib/metaruby/dsls/find_through_method_missing.rb
108
108
  - lib/metaruby/gui.rb
109
+ - lib/metaruby/gui/exception_rendering.rb
109
110
  - lib/metaruby/gui/exception_view.rb
110
111
  - lib/metaruby/gui/html.rb
111
112
  - lib/metaruby/gui/html/button.rb