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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: edefd7e59dcbf75b2cd69877ae482a9cb6838b96
4
- data.tar.gz: 4d1263ce781eec239a82dbf30c470e95b9e5030d
3
+ metadata.gz: 0f6d60aa23a3e9e790ac1613c65fc2a0b446f0de
4
+ data.tar.gz: e22d9104e853727888c91504b5d25dbf29234e9a
5
5
  SHA512:
6
- metadata.gz: 2e687ba3e7144b5f21f6ce767ed38364b9baf863ca8bc0b03ee353fbc159265f79569e1f8c7819365f78443e4a2650b40bdb96ae2e2d6653e2b23c6e5bf0643e
7
- data.tar.gz: 7da81dcac85b7e7546734d5eafebe64fa280d59fa5eb579d1ee15b71b2282db7c7aeb09d6c53fa0d018dd2b0368b79a061a30d449b77ada89b9f5ed7ff4e0e95
6
+ metadata.gz: e59cba378c250b744c75cd654c426cbbd801812df83e45a07fe2ba22ef15a903490d61d039ea67cdfc275e2dbf629739f1507f30ef16aacd79b52f8948be0c3f
7
+ data.tar.gz: 58bee189d56019dab2103b3944d3ec24001e044ce16dd76ca3101f9ff097652c44dbdabc6862affeed7f1a522fd7b839c54da0a016236c57447adb1591126de5
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  .yardoc
2
2
  coverage/
3
3
  doc/
4
+ .*.sw?
data/.travis.yml CHANGED
@@ -1,5 +1,9 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  rvm:
3
4
  - 2.0.0
4
5
  - 2.1.6
5
6
  - 2.2.2
7
+ script:
8
+ - bundle exec rake
9
+ - bundle exec rake test
data/README.md CHANGED
@@ -96,7 +96,7 @@ purpose, that we strongly recommend you use:
96
96
  ~~~
97
97
  class Module
98
98
  def color(name, &block)
99
- MetaRuby::ModelAsModule.create_ang_register_submodel(self, name, Color, &block)
99
+ MetaRuby::ModelAsModule.create_and_register_submodel(self, name, Color, &block)
100
100
  end
101
101
  end
102
102
  ~~~
@@ -305,9 +305,9 @@ Car.clear_submodels
305
305
 
306
306
  This will only clear anonymous models. Models that are created either by
307
307
  subclassing a model class or by using
308
- {MetaRuby::ModelAsModule#create_ang_register_submodel
309
- create_ang_register_submodel} are marked as
310
- {MetaRuby::Registration#permanent_model? permanent models} and therefore
308
+ {MetaRuby::ModelAsModule.create_and_register_submodel}
309
+ are marked as
310
+ {MetaRuby::Registration#permanent_model?} and therefore
311
311
  protected from removal by #clear_submodel
312
312
 
313
313
  # Adding options to the submodel creation process
data/lib/metaruby.rb CHANGED
@@ -1,17 +1,24 @@
1
1
  require 'utilrb/object/attribute'
2
+ require 'weakref'
2
3
 
3
4
  require 'metaruby/inherited_attribute'
4
5
  require 'metaruby/registration'
5
6
  require 'metaruby/module'
6
7
  require 'metaruby/class'
7
8
 
9
+ require 'utilrb/logger'
10
+
8
11
  # The toplevel namespace for MetaRuby
9
12
  #
10
13
  # MetaRuby is an implementation of a (very small) modelling toolkit that uses
11
14
  # the Ruby type system as its meta-metamodel
12
- require 'utilrb/logger'
13
15
  module MetaRuby
16
+ # Path to the metaruby.rb file (i.e. the root of the MetaRuby library)
17
+ #
18
+ # This is used to find ressources (css, javascript) that is bundled in the
19
+ # metaruby repository
14
20
  LIB_DIR = File.expand_path('metaruby', File.dirname(__FILE__))
21
+
15
22
  extend Logger::Root('MetaRuby', Logger::WARN)
16
23
  end
17
24
 
@@ -28,6 +28,8 @@ module MetaRuby
28
28
  # @return [String] set or get the documentation text for this model
29
29
  inherited_single_value_attribute :doc
30
30
 
31
+ # @!attribute [rw] name
32
+ #
31
33
  # Sets a name on this model
32
34
  #
33
35
  # Only use this on 'anonymous models', i.e. on models that are not
@@ -35,6 +37,9 @@ module MetaRuby
35
37
  #
36
38
  # @return [String] the assigned name
37
39
  def name=(name)
40
+ # This is dynamically defined. The reason is that there is no way to
41
+ # call 'super' to get the default Class#name, so we define our name
42
+ # only when it is explicitely assigned
38
43
  def self.name
39
44
  if @name then @name
40
45
  else super
@@ -69,17 +74,14 @@ module MetaRuby
69
74
  # assigned on a Ruby constant
70
75
  #
71
76
  # @return [Module] a subclass of self
72
- def new_submodel(options = Hash.new, &block)
73
- options, submodel_options = Kernel.filter_options options,
74
- :name => nil
75
-
77
+ def new_submodel(name: nil, **submodel_options, &block)
76
78
  Thread.current[FROM_NEW_SUBMODEL_TLS] = true
77
79
  model = self.class.new(self)
78
80
  model.permanent_model = false
79
- if options[:name]
80
- model.name = options[:name]
81
+ if name
82
+ model.name = name
81
83
  end
82
- setup_submodel(model, submodel_options, &block)
84
+ setup_submodel(model, **submodel_options, &block)
83
85
  model
84
86
  end
85
87
 
@@ -89,8 +91,10 @@ module MetaRuby
89
91
  end
90
92
 
91
93
  # Called at the end of the definition of a new submodel
92
- def setup_submodel(submodel, options = Hash.new, &block)
93
- register_submodel(submodel)
94
+ def setup_submodel(submodel, register: true, **options, &block)
95
+ if register
96
+ register_submodel(submodel)
97
+ end
94
98
 
95
99
  if block_given?
96
100
  submodel.apply_block(&block)
data/lib/metaruby/dsls.rb CHANGED
@@ -1,2 +1,8 @@
1
1
  require 'metaruby/dsls/doc'
2
2
  require 'metaruby/dsls/find_through_method_missing'
3
+
4
+ module MetaRuby
5
+ # Helper functions to build DSLs
6
+ module DSLs
7
+ end
8
+ end
data/lib/metaruby/gui.rb CHANGED
@@ -1,9 +1,25 @@
1
1
  require 'Qt4'
2
2
  require 'qtwebkit'
3
3
  require 'kramdown'
4
+ require 'pp'
4
5
  require 'metaruby/gui/html'
5
6
  require 'metaruby/gui/ruby_constants_item_model'
6
7
  require 'metaruby/gui/rendering_manager'
7
8
  require 'metaruby/gui/model_browser'
8
9
  require 'metaruby/gui/model_selector'
9
10
  require 'metaruby/gui/exception_view'
11
+
12
+ module MetaRuby
13
+ # Set of widgets and classes that are used to view/browse MetaRuby-based models using Qt
14
+ #
15
+ # Model views are using HTML, the rendering of which is done through
16
+ # {GUI::HTML::Page}. The main functionality centers around
17
+ # {GUI::ModelBrowser} which allows to browse models in a hierarchy, and
18
+ # display them in a HTML::Page.
19
+ #
20
+ # {GUI::ExceptionRendering} allows to render exceptions into a HTML page as
21
+ # well, the formatting being delegated to the exception's #pretty_print
22
+ # method.
23
+ module GUI
24
+ end
25
+ end
@@ -0,0 +1,281 @@
1
+ module MetaRuby
2
+ module GUI
3
+ # Functionality to render exceptions in an HTML view
4
+ #
5
+ # On top of properly formatting the exception, it introduces backtrace
6
+ # filtering and javascript-based buttons to enable backtraces on or off.
7
+ #
8
+ # It is usually not used directly, but through {HTML::Page}
9
+ #
10
+ # @see HTML::Page#enable_exception_rendering
11
+ # @see HTML::Page#push_exception
12
+ class ExceptionRendering
13
+ # The directory relative to which ressources (such as css or javascript
14
+ # files) are resolved by default
15
+ RESSOURCES_DIR = File.expand_path('html', File.dirname(__FILE__))
16
+
17
+ # @return [#link_to] an object that allows to render a link to an
18
+ # object
19
+ attr_reader :linker
20
+
21
+ # @return [#[]] an object that can be used to determine whether a
22
+ # file is a user or framework file. It is used in backtrace
23
+ # filtering and rendering. The default returns true for any file.
24
+ attr_reader :user_file_filter
25
+
26
+ # Sets {#user_file_filter} or resets it to the default
27
+ #
28
+ # @param [nil,#[]] filter
29
+ def user_file_filter=(filter)
30
+ @user_file_filter = filter || Hash.new(true)
31
+ end
32
+
33
+ # Create an exception rendering object using the given linker object
34
+ #
35
+ # @param [#link_to] linker
36
+ def initialize(linker)
37
+ @linker = linker
38
+ self.user_file_filter = nil
39
+ end
40
+
41
+ # Necessary header content
42
+ HEADER = <<-EOD
43
+ <link rel="stylesheet" href="file://#{File.join(RESSOURCES_DIR, 'exception_view.css')}" type="text/css" />
44
+ <script type="text/javascript" src="file://#{File.join(RESSOURCES_DIR, 'jquery.min.js')}"></script>
45
+ EOD
46
+
47
+ # The scripts that are used by the other exception templates
48
+ SCRIPTS = <<-EOD
49
+ <script type="text/javascript">
50
+ $(document).ready(function () {
51
+ $(".backtrace").hide()
52
+ $("a.backtrace_toggle_filtered").click(function (event) {
53
+ var eventId = $(this).attr("id");
54
+ $("#backtrace_full_" + eventId).hide();
55
+ $("#backtrace_filtered_" + eventId).toggle();
56
+ event.preventDefault();
57
+ });
58
+ $("a.backtrace_toggle_full").click(function (event) {
59
+ var eventId = $(this).attr("id");
60
+ $("#backtrace_full_" + eventId).toggle();
61
+ $("#backtrace_filtered_" + eventId).hide();
62
+ event.preventDefault();
63
+ });
64
+ });
65
+ </script>
66
+ EOD
67
+
68
+ # Contents necessary in the <head> ... </head> section
69
+ #
70
+ # It is used when enabling the renderer on a [Page] by calling
71
+ # {HTML::Page#add_to_setup}
72
+ def head
73
+ HEADER
74
+ end
75
+
76
+ # Scripts block to be added to the HTML document
77
+ #
78
+ # It is used when enabling the renderer on a [Page] by calling
79
+ # {HTML::Page#add_to_setup}
80
+ def scripts
81
+ SCRIPTS
82
+ end
83
+
84
+ # Parse a backtrace into its file, line and method consistuents
85
+ #
86
+ # @return [Array<(String,Integer,String)>]
87
+ def self.parse_backtrace(backtrace)
88
+ BacktraceParser.new(backtrace).parse
89
+ end
90
+
91
+ # Shim class that parses a backtrace into its constituents
92
+ #
93
+ # This is an internal class, that should not be used directly. Use
94
+ # {ExceptionRendering.parse_backtrace} instead.
95
+ #
96
+ # It provides the methods required for facet's #call_stack method to
97
+ # work, thus allowing to use it to parse an arbitrary backtrace
98
+ class BacktraceParser
99
+ # Create a parser for the given backtrace
100
+ def initialize(backtrace)
101
+ @backtrace = backtrace || []
102
+ end
103
+
104
+ # Parse the backtrace into file, line and method
105
+ #
106
+ # @return [Array<(String,Integer,String)>]
107
+ def parse
108
+ call_stack(0)
109
+ end
110
+
111
+ # Returns the backtrace
112
+ #
113
+ # This is required by facet's #call_stack
114
+ def pp_callstack(level)
115
+ @backtrace[level..-1]
116
+ end
117
+
118
+ # Returns the backtrace
119
+ #
120
+ # This is required by facet's #call_stack
121
+ def pp_call_stack(level)
122
+ @backtrace[level..-1]
123
+ end
124
+ end
125
+
126
+ # Template used to render an exception that does not have backtrace
127
+ EXCEPTION_TEMPLATE_WITHOUT_BACKTRACE = <<-EOF
128
+ <div class="message" id="<%= id %>"><pre><%= message.join("\n") %></pre></div>
129
+ EOF
130
+
131
+ # Template used to render an exception that does have a backtrace
132
+ EXCEPTION_TEMPLATE_WITH_BACKTRACE = <<-EOF
133
+ <div class="message" id="<%= id %>">
134
+ <pre><%= message.join("\n") %></pre>
135
+ <span class="backtrace_links">
136
+ (show: <a class="backtrace_toggle_filtered" id="<%= id %>">filtered backtrace</a>,
137
+ <a class=\"backtrace_toggle_full\" id="<%= id %>">full backtrace</a>)
138
+ </span>
139
+ </div>
140
+ <div class="backtrace_summary">
141
+ from <%= origin_file %>:<%= origin_line %>:in <%= HTML.escape_html(origin_method.to_s) %>
142
+ </div>
143
+ <div class="backtrace" id="backtrace_filtered_<%= id %>">
144
+ <%= render_backtrace(filtered_backtrace) %>
145
+ </div>
146
+ <div class="backtrace" id="backtrace_full_<%= id %>">
147
+ <%= render_backtrace(full_backtrace) %>
148
+ </div>
149
+ EOF
150
+
151
+ # Filters the backtrace to remove framework parts that are not
152
+ # relevant
153
+ #
154
+ # @param [Array<(String,Integer,Symbol)>] parsed_backtrace the parsed backtrace
155
+ # @param [Array<(String,Integer,Symbol)>] raw_backtrace the raw backtrace
156
+ def filter_backtrace(parsed_backtrace, raw_backtrace)
157
+ head = parsed_backtrace.take_while { |file, _| !user_file?(file) }
158
+ tail = parsed_backtrace[head.size..-1].find_all { |file, _| user_file?(file) }
159
+ head + tail
160
+ end
161
+
162
+ # Return true if the given file is a user file or a framework file
163
+ #
164
+ # An object used to determine this can be set with
165
+ # {#user_file_filter=}
166
+ #
167
+ # This is used by {#render_backtrace} to choose the style of a
168
+ # backtrace line
169
+ def user_file?(file)
170
+ user_file_filter[file]
171
+ end
172
+
173
+ @@exception_id = 0
174
+
175
+ # Automatically generate an exception ID
176
+ def allocate_exception_id
177
+ @@exception_id += 1
178
+ end
179
+
180
+ # Render an exception into HTML
181
+ #
182
+ # @param [Exception] e the exception to be rendered
183
+ # @param [String] reason additional string that describes the
184
+ # exception reason
185
+ # @param [String] id the ID that should be used to identify the
186
+ # exception. Since a given exception can "contain" more than one
187
+ # (see {#each_exception_from}), a -#counter pattern is added to
188
+ # the ID.
189
+ # @return [String]
190
+ def render(e, reason = nil, id = allocate_exception_id)
191
+ counter = 0
192
+ html = []
193
+ seen = Set.new
194
+ each_exception_from(e) do |exception|
195
+ if !seen.include?(exception)
196
+ seen << exception
197
+ html << render_single_exception(e, "#{id}-#{counter += 1}")
198
+ end
199
+ end
200
+ html.join("\n")
201
+ end
202
+
203
+ # Method used by {#render} to discover all exception objects that
204
+ # are linked to another exception, in cases where exceptions cause
205
+ # one another
206
+ #
207
+ # The default implementation only yields 'e', reimplement in
208
+ # subclasses
209
+ #
210
+ # @yieldparam [Exception] exception an exception
211
+ def each_exception_from(e)
212
+ return enum_for(__method__) if !block_given?
213
+ yield(e)
214
+ end
215
+
216
+ # @api private
217
+ #
218
+ # Parses the exception backtrace, and generate a parsed raw and
219
+ # parsed filtered version of it
220
+ #
221
+ # @return [(Array<(String,Integer,String)>,Array<(String,Integer,String))>
222
+ # the full and filtered backtraces, as list of tuples
223
+ # (file,line,method)
224
+ def parse_and_filter_backtrace(backtrace)
225
+ full_backtrace = ExceptionRendering.parse_backtrace(backtrace)
226
+ filtered_backtrace = filter_backtrace(full_backtrace, backtrace)
227
+ if filtered_backtrace.first.respond_to?(:to_str)
228
+ filtered_backtrace = ExceptionRendering.parse_backtrace(filtered_backtrace)
229
+ end
230
+ return full_backtrace, filtered_backtrace
231
+ end
232
+
233
+ # @api private
234
+ #
235
+ # Render a single exception object into a HTML block
236
+ #
237
+ # @param [Exception] e the exception
238
+ # @param [String] id the block ID
239
+ # @return [String]
240
+ def render_single_exception(e, id)
241
+ message = PP.pp(e, "").split("\n").
242
+ map { |line| HTML.escape_html(line) }
243
+
244
+ full_backtrace, filtered_backtrace =
245
+ parse_and_filter_backtrace(e.backtrace || Array.new)
246
+
247
+ if !full_backtrace.empty?
248
+ origin_file, origin_line, origin_method =
249
+ filtered_backtrace.find { |file, _| user_file?(file) } ||
250
+ filtered_backtrace.first ||
251
+ full_backtrace.first
252
+
253
+ origin_file = linker.link_to(Pathname.new(origin_file), origin_file, lineno: origin_line)
254
+ ERB.new(EXCEPTION_TEMPLATE_WITH_BACKTRACE).result(binding)
255
+ else
256
+ ERB.new(EXCEPTION_TEMPLATE_WITHOUT_BACKTRACE).result(binding)
257
+ end
258
+ end
259
+
260
+ # @api private
261
+ #
262
+ # Render a backtrace
263
+ #
264
+ # It uses {#linker} to generate links, and {#user_file?} to change
265
+ # the style of the backtrace line.
266
+ def render_backtrace(backtrace)
267
+ result = []
268
+ backtrace.each do |file, line, method|
269
+ file_link = linker.link_to(Pathname.new(file), file, lineno: line)
270
+ if user_file?(file)
271
+ result << " <span class=\"user_file\">#{file_link}:#{line}:in #{HTML.escape_html(method.to_s)}</span><br/>"
272
+ else
273
+ result << " #{file_link}:#{line}:in #{HTML.escape_html(method.to_s)}<br/>"
274
+ end
275
+ end
276
+ result.join("\n")
277
+ end
278
+ end
279
+ end
280
+ end
281
+