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.
- checksums.yaml +4 -4
- data/.travis.yml +6 -3
- data/Gemfile +6 -0
- data/Rakefile +12 -2
- data/lib/metaruby.rb +2 -0
- data/lib/metaruby/attributes.rb +52 -60
- data/lib/metaruby/backward/singleton_class_p.rb +14 -0
- data/lib/metaruby/dsls.rb +31 -1
- data/lib/metaruby/dsls/doc.rb +33 -25
- data/lib/metaruby/dsls/find_through_method_missing.rb +78 -16
- data/lib/metaruby/gui.rb +1 -0
- data/lib/metaruby/gui/html/exception_view.css +4 -4
- data/lib/metaruby/gui/html/page_body.rhtml +0 -3
- data/lib/metaruby/gui/model_browser.rb +35 -20
- data/lib/metaruby/gui/model_hierarchy.rb +267 -0
- data/lib/metaruby/gui/model_selector.rb +63 -40
- data/lib/metaruby/model_as_class.rb +9 -13
- data/lib/metaruby/model_as_module.rb +2 -5
- data/lib/metaruby/registration.rb +25 -19
- data/lib/metaruby/test.rb +3 -0
- data/lib/metaruby/version.rb +1 -1
- metadata +5 -4
@@ -18,11 +18,14 @@ module MetaRuby
|
|
18
18
|
# @return [Qt::SortFilterProxyModel]
|
19
19
|
attr_reader :model_filter
|
20
20
|
|
21
|
-
#
|
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 [
|
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 =
|
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(
|
69
|
-
|
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[
|
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]
|
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
|
-
|
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
|
-
|
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
|
-
|
211
|
-
|
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
|
221
|
-
|
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
|
-
|
232
|
-
|
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 !
|
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
|
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.
|
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
|
81
|
-
model
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
#
|
15
|
-
#
|
16
|
-
# @return [Array<
|
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
|
-
|
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
|
-
|
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
|
-
|
130
|
-
if !
|
131
|
-
deregister_submodels(
|
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
|
-
|
135
|
-
|
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
|
-
|
153
|
+
permanent.each { |m| m.clear_submodels }
|
148
154
|
# And this the non-permanent ones
|
149
|
-
|
155
|
+
non_permanent.each { |m| m.clear_submodels }
|
150
156
|
true
|
151
157
|
end
|
152
158
|
|
data/lib/metaruby/test.rb
CHANGED
data/lib/metaruby/version.rb
CHANGED
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:
|
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:
|
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.
|
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:
|