metaruby 1.0.0 → 2.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.
@@ -18,11 +18,14 @@ module MetaRuby
18
18
  # @return [Qt::SortFilterProxyModel]
19
19
  attr_reader :model_filter
20
20
 
21
- # (see {RubyConstantsItemModel#type_info)
21
+ # A mapping from a root model and the user-visible name for this
22
+ # root
23
+ #
24
+ # @return [Hash<Object,String>]
22
25
  attr_reader :type_info
23
26
 
24
27
  # The Qt item model that represents the object hierarchy
25
- # @return [RubyConstantsItemModel]
28
+ # @return [ModelHierarchy]
26
29
  attr_reader :browser_model
27
30
 
28
31
  # @return [Qt::PushButton] a button allowing to filter models by
@@ -41,9 +44,7 @@ module MetaRuby
41
44
  super
42
45
 
43
46
  @type_info = Hash.new
44
- @browser_model = RubyConstantsItemModel.new(type_info) do |mod|
45
- model?(mod)
46
- end
47
+ @browser_model = ModelHierarchy.new
47
48
  @type_filters = Hash.new
48
49
 
49
50
  layout = Qt::VBoxLayout.new(self)
@@ -65,12 +66,13 @@ module MetaRuby
65
66
  # objects of this type
66
67
  # @param [Integer] priority if an object's ancestry matches multiple
67
68
  # types, only the ones of the highest priority will be retained
68
- def register_type(model_base, name, priority = 0)
69
- type_info[model_base] = RubyConstantsItemModel::TypeInfo.new(name, priority)
69
+ def register_type(root_model, name, priority = 0, categories: [], resolver: ModelHierarchy::Resolver.new)
70
+ @browser_model.add_root(root_model, priority, categories: categories, resolver: resolver)
71
+ type_info[root_model] = name
70
72
  action = Qt::Action.new(name, self)
71
73
  action.checkable = true
72
74
  action.checked = true
73
- type_filters[model_base] = action
75
+ type_filters[root_model] = action
74
76
  btn_type_filter_menu.add_action(action)
75
77
  connect(action, SIGNAL('triggered()')) do
76
78
  update_model_filter
@@ -79,8 +81,13 @@ module MetaRuby
79
81
 
80
82
  # Update the view, reloading the underlying model
81
83
  def update
82
- update_model_filter
83
84
  reload
85
+ update_model_filter
86
+ end
87
+
88
+ # (see ModelHierarchy#find_resolver_from_model)
89
+ def find_resolver_from_model(model)
90
+ @browser_model.find_resolver_from_model(model)
84
91
  end
85
92
 
86
93
  # @api private
@@ -89,10 +96,10 @@ module MetaRuby
89
96
  def update_model_filter
90
97
  type_rx = type_filters.map do |model_base, act|
91
98
  if act.checked?
92
- type_info[model_base].name
99
+ type_info[model_base]
93
100
  end
94
101
  end
95
- type_rx = type_rx.compact.join("|")
102
+ type_rx = type_rx.compact.join(",|,")
96
103
 
97
104
  model_filter.filter_role = Qt::UserRole # this contains the keywords (ancestry and/or name)
98
105
  # This workaround a problem that I did not have time to
@@ -104,10 +111,38 @@ module MetaRuby
104
111
  # The pattern has to match every element in the hierarchy. We
105
112
  # achieve this by making the suffix part optional
106
113
  name_rx = filter_box.text.downcase.gsub(/:+/, "/")
107
- model_filter.filter_reg_exp = Qt::RegExp.new("(#{type_rx}).*;.*#{name_rx}")
114
+ name_rx = '[^;]*,[^,]*' + name_rx.split('/').join("[^,]*,[^;]*;[^;]*,") + '[^,]*,[^;]*'
115
+ regexp = Qt::RegExp.new("(,#{type_rx},)[^;]*;([^;]*;)*#{name_rx}")
116
+ regexp.case_sensitivity = Qt::CaseInsensitive
117
+ model_filter.filter_reg_exp = regexp
118
+ model_filter.invalidate
108
119
  auto_open
109
120
  end
110
121
 
122
+ def filter_row_count(parent = Qt::ModelIndex.new)
123
+ model_filter.row_count(parent)
124
+ end
125
+
126
+ def model_items_from_filter(parent = Qt::ModelIndex.new)
127
+ (0...filter_row_count(parent)).map do |i|
128
+ model_item_from_filter_row(i, parent)
129
+ end
130
+ end
131
+
132
+ def model_item_from_filter_row(row, parent = Qt::ModelIndex.new)
133
+ filter_index = model_filter.index(row, 0, parent)
134
+ model_index = model_filter.map_to_source(filter_index)
135
+ return browser_model.item_from_index(model_index), filter_index
136
+ end
137
+
138
+ def dump_filtered_item_model(parent = Qt::ModelIndex.new, indent = "")
139
+ model_items_from_filter(parent).each_with_index do |(model_item, filter_index), i|
140
+ data = model_item.data(Qt::UserRole).to_string
141
+ puts "#{indent}[#{i}] #{model_item.text} #{data}"
142
+ dump_filtered_item_model(filter_index, indent + " ")
143
+ end
144
+ end
145
+
111
146
  # Auto-open in the current state
112
147
  #
113
148
  # @param [Integer] threshold the method opens items whose number of
@@ -135,20 +170,12 @@ module MetaRuby
135
170
  end
136
171
  end
137
172
 
138
- # Tests if an object if a model
139
- def model?(obj)
140
- type_info.any? do |model_base, _|
141
- obj.kind_of?(model_base) ||
142
- (obj.kind_of?(Module) && obj <= model_base)
143
- end
144
- end
145
-
146
173
  class ModelPathCompleter < Qt::Completer
147
174
  def splitPath(path)
148
175
  path.split('/')
149
176
  end
150
177
  def pathFromIndex(index)
151
- index.data(Qt::UserRole).split(";").last
178
+ index.data(Qt::UserRole).to_string.split(";").last
152
179
  end
153
180
  end
154
181
 
@@ -187,10 +214,11 @@ module MetaRuby
187
214
  @model_list = Qt::TreeView.new(self)
188
215
  @model_filter = Qt::SortFilterProxyModel.new
189
216
  model_filter.filter_case_sensitivity = Qt::CaseInsensitive
190
- model_filter.dynamic_sort_filter = true
191
217
  model_filter.filter_role = Qt::UserRole
192
- model_list.model = model_filter
218
+ model_filter.dynamic_sort_filter = true
193
219
  model_filter.source_model = browser_model
220
+ model_filter.sort(0)
221
+ model_list.model = model_filter
194
222
 
195
223
  @filter_box = Qt::LineEdit.new(self)
196
224
  filter_box.connect(SIGNAL('textChanged(QString)')) do |text|
@@ -207,9 +235,8 @@ module MetaRuby
207
235
 
208
236
  model_list.selection_model.connect(SIGNAL('currentChanged(const QModelIndex&, const QModelIndex&)')) do |index, _|
209
237
  index = model_filter.map_to_source(index)
210
- mod = browser_model.info_from_index(index)
211
- if model?(mod.this)
212
- emit model_selected(Qt::Variant.from_ruby(mod.this, mod.this))
238
+ if model = browser_model.find_model_from_index(index)
239
+ emit model_selected(Qt::Variant.from_ruby(model, model))
213
240
  end
214
241
  end
215
242
  end
@@ -217,19 +244,15 @@ module MetaRuby
217
244
 
218
245
  # Reload the object model, keeping the current selection if possible
219
246
  def reload
220
- if current = current_selection
221
- current_module = current.this
222
- current_path = []
223
- while current
224
- current_path.unshift current.name
225
- current = current.parent
226
- end
247
+ if current_model = current_selection
248
+ current_path = @browser_model.find_path_from_model(current_model)
227
249
  end
228
250
 
229
251
  browser_model.reload
230
-
231
- if current_path && !select_by_path(*current_path)
232
- select_by_module(current_module)
252
+ if current_path
253
+ select_by_path(*current_path)
254
+ elsif current_model
255
+ select_by_model(current_model)
233
256
  end
234
257
  end
235
258
 
@@ -258,10 +281,10 @@ module MetaRuby
258
281
  if !index
259
282
  return
260
283
  elsif !index.valid?
261
- if !options[:reset_filter]
284
+ if !reset_filter
262
285
  return index
263
286
  end
264
- reset_filter
287
+ self.reset_filter
265
288
  model_filter.map_from_source(source_index)
266
289
  else index
267
290
  end
@@ -285,7 +308,7 @@ module MetaRuby
285
308
  #
286
309
  # @return [Boolean] true if the path resolved to something known,
287
310
  # and false otherwise
288
- def select_by_module(model)
311
+ def select_by_model(model)
289
312
  if index = browser_model.find_index_by_model(model)
290
313
  index = map_index_from_source(index)
291
314
  model_list.current_index = index
@@ -300,7 +323,7 @@ module MetaRuby
300
323
  index = model_list.selection_model.current_index
301
324
  if index.valid?
302
325
  index = model_filter.map_to_source(index)
303
- browser_model.info_from_index(index)
326
+ browser_model.find_model_from_index(index)
304
327
  end
305
328
  end
306
329
 
@@ -72,13 +72,15 @@ module MetaRuby
72
72
  # assigned on a Ruby constant
73
73
  #
74
74
  # @return [Module] a subclass of self
75
- def new_submodel(name: nil, **submodel_options, &block)
75
+ def new_submodel(name: nil, register: true, **submodel_options, &block)
76
76
  Thread.current[FROM_NEW_SUBMODEL_TLS] = true
77
77
  model = self.class.new(self)
78
78
  model.permanent_model = false
79
+ model.instance_variable_set :@name, nil
80
+ model.name = name if name
79
81
  setup_submodel(model, **submodel_options, &block)
80
- if name
81
- model.name = name
82
+ if register
83
+ register_submodel(model)
82
84
  end
83
85
  model
84
86
  end
@@ -90,15 +92,7 @@ module MetaRuby
90
92
 
91
93
  # Called at the end of the definition of a new submodel
92
94
  def setup_submodel(submodel, register: true, **options, &block)
93
- submodel.instance_variable_set :@name, nil
94
-
95
- if register
96
- register_submodel(submodel)
97
- end
98
-
99
- if block_given?
100
- submodel.apply_block(&block)
101
- end
95
+ submodel.apply_block(&block) if block
102
96
  end
103
97
 
104
98
  # Registers submodels when a subclass is created
@@ -108,7 +102,7 @@ module MetaRuby
108
102
 
109
103
  subclass.definition_location =
110
104
  if MetaRuby.keep_definition_location?
111
- call_stack
105
+ caller_locations
112
106
  else Array.new
113
107
  end
114
108
  subclass.instance_variable_set :@name, nil
@@ -116,7 +110,9 @@ module MetaRuby
116
110
  subclass.permanent_model = subclass.accessible_by_name? &&
117
111
  subclass.permanent_definition_context?
118
112
  if !from_new_submodel
113
+ subclass.instance_variable_set :@name, nil
119
114
  setup_submodel(subclass)
115
+ register_submodel(subclass)
120
116
  end
121
117
  end
122
118
 
@@ -121,13 +121,10 @@ module MetaRuby
121
121
  def new_submodel(name: nil, type: self.class, **submodel_options, &block)
122
122
  model = type.new
123
123
  model.extend ModelAsModule
124
- model.name =
125
- if name
126
- name.dup
127
- end
124
+ model.name = name.dup if name
128
125
  model.definition_location =
129
126
  if MetaRuby.keep_definition_location?
130
- call_stack
127
+ caller_locations
131
128
  else Array.new
132
129
  end
133
130
  setup_submodel(model, submodel_options, &block)
@@ -1,6 +1,5 @@
1
1
  require 'facets/module/spacename'
2
2
  require 'facets/module/basename'
3
- require 'facets/kernel/call_stack'
4
3
  require 'utilrb/object/attribute'
5
4
  require 'utilrb/module/attr_predicate'
6
5
 
@@ -11,9 +10,9 @@ module MetaRuby
11
10
  # returns the model that is parent of +self+
12
11
  module Registration
13
12
  # The place where this model got defined in the source code
14
- # The tuple is (file,lineno,method), and can be obtained with
15
- # facet's #call_stack
16
- # @return [Array<(String,Integer,Symbol)>]
13
+ # This is an array of Thread::Backtrace::Locations
14
+ #
15
+ # @return [Array<Thread::Backtrace::Locations>]
17
16
  attr_accessor :definition_location
18
17
 
19
18
  # Tells {#clear_submodels} whether this model should be removed from
@@ -69,10 +68,14 @@ module MetaRuby
69
68
 
70
69
  # Call to register a model that is a submodel of +self+
71
70
  def register_submodel(klass)
71
+ if klass.singleton_class?
72
+ raise ArgumentError, "cannot register a singleton class"
73
+ end
74
+
72
75
  if !klass.definition_location
73
76
  klass.definition_location =
74
77
  if MetaRuby.keep_definition_location?
75
- call_stack
78
+ caller_locations
76
79
  else Array.new
77
80
  end
78
81
  end
@@ -108,12 +111,19 @@ module MetaRuby
108
111
  if m = supermodel
109
112
  m.deregister_submodels([self])
110
113
  end
111
- if Registration.accessible_by_name?(self)
112
- Registration.deregister_constant(self)
113
- end
114
+ clear_registration_as_constant
114
115
  end
115
116
  clear_submodels
116
117
  end
118
+
119
+ # Removes any constant this model is registered as
120
+ def clear_registration_as_constant
121
+ # Deregister non-permanent models that are registered in the
122
+ # constant hierarchy
123
+ if Registration.accessible_by_name?(self)
124
+ Registration.deregister_constant(self)
125
+ end
126
+ end
117
127
 
118
128
  # Removes the constant that stores the given object in the Ruby constant
119
129
  # hierarchy
@@ -126,17 +136,13 @@ module MetaRuby
126
136
 
127
137
  # Recursively deregisters all non-permanent submodels
128
138
  def clear_submodels
129
- children = each_submodel.find_all { |m| !m.permanent_model? }
130
- if !children.empty?
131
- deregister_submodels(children)
139
+ permanent, non_permanent = each_submodel.partition { |m| m.permanent_model? }
140
+ if !non_permanent.empty?
141
+ deregister_submodels(non_permanent)
132
142
  end
133
143
 
134
- children.each do |m|
135
- # Deregister non-permanent models that are registered in the
136
- # constant hierarchy
137
- if Registration.accessible_by_name?(m)
138
- Registration.deregister_constant(m)
139
- end
144
+ non_permanent.each do |m|
145
+ m.clear_registration_as_constant
140
146
  end
141
147
 
142
148
  # This contains the permanent submodels
@@ -144,9 +150,9 @@ module MetaRuby
144
150
  # We can call #clear_submodels while iterating here as it is a
145
151
  # constraint that all models in #submodels are permanent (and
146
152
  # will therefore not be removed)
147
- each_submodel { |m| m.clear_submodels }
153
+ permanent.each { |m| m.clear_submodels }
148
154
  # And this the non-permanent ones
149
- children.each { |m| m.clear_submodels }
155
+ non_permanent.each { |m| m.clear_submodels }
150
156
  true
151
157
  end
152
158
 
@@ -31,6 +31,9 @@ if ENV['TEST_ENABLE_PRY'] != '0'
31
31
  end
32
32
  end
33
33
 
34
+ FlexMock.partials_are_based = true
35
+ FlexMock.partials_verify_signatures = true
36
+
34
37
  module MetaRuby
35
38
  # This module is the common setup for all tests
36
39
  #
@@ -1,4 +1,4 @@
1
1
  module MetaRuby
2
2
  # The metaruby library version
3
- VERSION = "1.0.0"
3
+ VERSION = "2.0.0"
4
4
  end
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
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-18 00:00:00.000000000 Z
11
+ date: 2018-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: utilrb
@@ -102,6 +102,7 @@ files:
102
102
  - bin/.gitattributes
103
103
  - lib/metaruby.rb
104
104
  - lib/metaruby/attributes.rb
105
+ - lib/metaruby/backward/singleton_class_p.rb
105
106
  - lib/metaruby/dsls.rb
106
107
  - lib/metaruby/dsls/doc.rb
107
108
  - lib/metaruby/dsls/find_through_method_missing.rb
@@ -124,6 +125,7 @@ files:
124
125
  - lib/metaruby/gui/html/page_body.rhtml
125
126
  - lib/metaruby/gui/html/rock-website.css
126
127
  - lib/metaruby/gui/model_browser.rb
128
+ - lib/metaruby/gui/model_hierarchy.rb
127
129
  - lib/metaruby/gui/model_selector.rb
128
130
  - lib/metaruby/gui/rendering_manager.rb
129
131
  - lib/metaruby/gui/ruby_constants_item_model.rb
@@ -155,9 +157,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  version: '0'
156
158
  requirements: []
157
159
  rubyforge_project:
158
- rubygems_version: 2.2.3
160
+ rubygems_version: 2.5.1
159
161
  signing_key:
160
162
  specification_version: 4
161
163
  summary: Modelling using the Ruby language as a metamodel
162
164
  test_files: []
163
- has_rdoc: