metaruby 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: