ronin 0.2.1 → 0.2.2

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.
Files changed (80) hide show
  1. data/History.txt +25 -0
  2. data/Manifest.txt +36 -11
  3. data/README.txt +6 -8
  4. data/Rakefile +2 -1
  5. data/lib/ronin/config.rb +0 -3
  6. data/lib/ronin/environment.rb +1 -1
  7. data/lib/ronin/extensions/string.rb +0 -11
  8. data/lib/ronin/formatting/extensions/binary/integer.rb +24 -12
  9. data/lib/ronin/formatting/extensions/binary/string.rb +166 -0
  10. data/lib/ronin/formatting/extensions/text/string.rb +4 -4
  11. data/lib/ronin/license.rb +42 -12
  12. data/lib/ronin/os.rb +3 -2
  13. data/lib/ronin/platform/extension.rb +11 -141
  14. data/lib/ronin/platform/extension_cache.rb +11 -0
  15. data/lib/ronin/platform/overlay.rb +56 -25
  16. data/lib/ronin/platform/overlay_cache.rb +1 -1
  17. data/lib/ronin/platform/platform.rb +14 -3
  18. data/lib/ronin/platform/ronin.rb +20 -1
  19. data/lib/ronin/platform/tasks/spec.rb +9 -0
  20. data/lib/ronin/{chars.rb → static.rb} +2 -2
  21. data/lib/ronin/static/finders.rb +144 -0
  22. data/lib/ronin/static/static.rb +53 -0
  23. data/lib/ronin/ui/command_line/commands/add.rb +21 -5
  24. data/lib/ronin/ui/command_line/commands/install.rb +19 -3
  25. data/lib/ronin/ui/command_line/commands/rm.rb +1 -1
  26. data/lib/ronin/ui/command_line/commands/uninstall.rb +1 -1
  27. data/lib/ronin/ui/command_line/commands/update.rb +9 -2
  28. data/lib/ronin/version.rb +1 -1
  29. data/spec/extensions/string_spec.rb +0 -10
  30. data/spec/formatting/binary/helpers/hexdumps.rb +14 -0
  31. data/spec/formatting/binary/helpers/hexdumps/hexdump_decimal_shorts.txt +17 -0
  32. data/spec/formatting/binary/helpers/hexdumps/hexdump_hex_bytes.txt +17 -0
  33. data/spec/formatting/binary/helpers/hexdumps/hexdump_hex_shorts.txt +17 -0
  34. data/spec/formatting/binary/helpers/hexdumps/hexdump_octal_bytes.txt +17 -0
  35. data/spec/formatting/binary/helpers/hexdumps/hexdump_octal_shorts.txt +17 -0
  36. data/spec/formatting/binary/helpers/hexdumps/hexdump_repeated.txt +6 -0
  37. data/spec/formatting/binary/helpers/hexdumps/od_decimal_bytes.txt +17 -0
  38. data/spec/formatting/binary/helpers/hexdumps/od_decimal_ints.txt +17 -0
  39. data/spec/formatting/binary/helpers/hexdumps/od_decimal_quads.txt +17 -0
  40. data/spec/formatting/binary/helpers/hexdumps/od_decimal_shorts.txt +17 -0
  41. data/spec/formatting/binary/helpers/hexdumps/od_hex_bytes.txt +17 -0
  42. data/spec/formatting/binary/helpers/hexdumps/od_hex_ints.txt +17 -0
  43. data/spec/formatting/binary/helpers/hexdumps/od_hex_quads.txt +17 -0
  44. data/spec/formatting/binary/helpers/hexdumps/od_hex_shorts.txt +17 -0
  45. data/spec/formatting/binary/helpers/hexdumps/od_octal_bytes.txt +17 -0
  46. data/spec/formatting/binary/helpers/hexdumps/od_octal_ints.txt +17 -0
  47. data/spec/formatting/binary/helpers/hexdumps/od_octal_quads.txt +17 -0
  48. data/spec/formatting/binary/helpers/hexdumps/od_octal_shorts.txt +17 -0
  49. data/spec/formatting/binary/helpers/hexdumps/od_repeated.txt +6 -0
  50. data/spec/formatting/binary/helpers/hexdumps/repeated.bin +1 -0
  51. data/spec/formatting/binary/integer_spec.rb +61 -1
  52. data/spec/formatting/binary/string_spec.rb +166 -9
  53. data/spec/platform/extension_cache_spec.rb +8 -0
  54. data/spec/platform/helpers/overlays.yaml.erb +3 -0
  55. data/spec/platform/helpers/overlays/hello/ronin.xml +1 -1
  56. data/spec/platform/helpers/overlays/random/random/extension.rb +7 -0
  57. data/spec/platform/helpers/overlays/random/ronin.xml +26 -0
  58. data/spec/platform/helpers/overlays/test1/ronin.xml +2 -2
  59. data/spec/platform/helpers/overlays/test2/ronin.xml +2 -2
  60. data/spec/platform/overlay_cache_spec.rb +5 -3
  61. data/spec/platform/overlay_spec.rb +35 -0
  62. data/spec/platform/ronin_spec.rb +13 -1
  63. data/spec/static/finders_spec.rb +55 -0
  64. data/spec/static/helpers/static.rb +11 -0
  65. data/spec/static/helpers/static1/dir/two.txt +0 -0
  66. data/spec/static/helpers/static1/one.txt +0 -0
  67. data/spec/static/helpers/static2/dir/two.txt +0 -0
  68. data/spec/static/helpers/static_class.rb +7 -0
  69. data/spec/static/static_spec.rb +24 -0
  70. data/static/{overlay.xsl → ronin/platform/overlay.xsl} +0 -0
  71. metadata +50 -17
  72. data/bin/ronin-ext +0 -12
  73. data/bin/ronin-overlay +0 -12
  74. data/lib/ronin/chars/char_set.rb +0 -198
  75. data/lib/ronin/chars/chars.rb +0 -190
  76. data/lib/ronin/ui/command_line/commands/ext.rb +0 -70
  77. data/lib/ronin/ui/command_line/commands/overlay.rb +0 -189
  78. data/spec/chars/char_set_spec.rb +0 -175
  79. data/spec/chars/chars_spec.rb +0 -107
  80. data/static/extension.rb +0 -9
@@ -21,7 +21,7 @@
21
21
  #++
22
22
  #
23
23
 
24
- require 'ronin/chars'
24
+ require 'chars'
25
25
 
26
26
  class String
27
27
 
@@ -31,11 +31,11 @@ class String
31
31
  #
32
32
  # _options_ may include the following keys:
33
33
  # <tt>:included</tt>:: The set of characters that will be formated,
34
- # defaults to <tt>Ronin::Chars.all</tt>.
34
+ # defaults to <tt>Chars.all</tt>.
35
35
  # <tt>:excluded</tt>:: The characters not to format.
36
36
  #
37
37
  def format_chars(options={},&block)
38
- included = (options[:included] || Ronin::Chars.all)
38
+ included = (options[:included] || Chars.all)
39
39
  excluded = (options[:excluded] || [])
40
40
 
41
41
  targeted = included - excluded
@@ -60,7 +60,7 @@ class String
60
60
  #
61
61
  # _options_ may include the following keys:
62
62
  # <tt>:included</tt>:: The set of characters that will be formated,
63
- # defaults to <tt>Ronin::Chars.all</tt>.
63
+ # defaults to <tt>Chars.all</tt>.
64
64
  # <tt>:excluded</tt>:: The characters not to format.
65
65
  #
66
66
  def format_bytes(options={},&block)
data/lib/ronin/license.rb CHANGED
@@ -22,7 +22,6 @@
22
22
  #
23
23
 
24
24
  require 'ronin/model'
25
- require 'ronin/extensions/string'
26
25
 
27
26
  require 'dm-predefined'
28
27
 
@@ -65,24 +64,55 @@ module Ronin
65
64
  # <tt>:url</tt>:: The URL to the license.
66
65
  #
67
66
  def self.define(name,options={})
68
- super(name.to_method_name,options.merge(:name => name))
67
+ super(name.downcase.gsub(/[\s_\-]+/,'_'),options.merge(:name => name))
69
68
  end
70
69
 
71
70
  # Creative Commons Licenses
72
- define 'CC by', :description => 'Creative Commons Attribution v3.0 License', :url => 'http://creativecommons.org/licenses/by/3.0/'
73
- define 'CC by-sa', :description => 'Creative Commons Attribution-Share Alike v3.0 License', :url => 'http://creativecommons.org/licenses/by-sa/3.0/'
74
- define 'CC by-nd', :description => 'Creative Commons Attribution-No Derivative Works v3.0 License', :url => 'http://creativecommons.org/licenses/by-nd/3.0/'
75
- define 'CC by-nc', :description => 'Creative Commons Attribution-Noncommercial v3.0 License', :url => 'http://creativecommons.org/licenses/by-nc/3.0/'
76
- define 'CC by-nc-sa', :description => 'Creative Commons Attribution-Noncommercial-Share Alike v3.0 License', :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/'
77
- define 'CC by-nc-nd', :description => 'Creative Commons Attribution-Noncommercial-No Derivative Works v3.0 License', :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/'
71
+ define 'CC by',
72
+ :description => 'Creative Commons Attribution v3.0 License',
73
+ :url => 'http://creativecommons.org/licenses/by/3.0/'
74
+
75
+ define 'CC by-sa',
76
+ :description => 'Creative Commons Attribution-Share Alike v3.0 License',
77
+ :url => 'http://creativecommons.org/licenses/by-sa/3.0/'
78
+
79
+ define 'CC by-nd',
80
+ :description => 'Creative Commons Attribution-No Derivative Works v3.0 License',
81
+ :url => 'http://creativecommons.org/licenses/by-nd/3.0/'
82
+
83
+ define 'CC by-nc',
84
+ :description => 'Creative Commons Attribution-Noncommercial v3.0 License',
85
+ :url => 'http://creativecommons.org/licenses/by-nc/3.0/'
86
+
87
+ define 'CC by-nc-sa',
88
+ :description => 'Creative Commons Attribution-Noncommercial-Share Alike v3.0 License',
89
+ :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/'
90
+
91
+ define 'CC by-nc-nd',
92
+ :description => 'Creative Commons Attribution-Noncommercial-No Derivative Works v3.0 License',
93
+ :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/'
94
+
95
+ define 'CC0',
96
+ :description => 'Creative Commons Zero License',
97
+ :url => 'http://creativecommons.org/licenses/zero/1.0/'
78
98
 
79
99
  # GNU Public Licenses
80
- define 'GPL-2', :description => 'GNU Public License v2.0', :url => 'http://www.gnu.org/licenses/gpl-2.0.txt'
81
- define 'GPL-3', :description => 'GNU Public License v3.0', :url => 'http://www.gnu.org/licenses/gpl-3.0.txt'
82
- define 'LGPL-3', :description => 'GNU Lesser General Public License v3.0', :url => 'http://www.gnu.org/licenses/lgpl-3.0.txt'
100
+ define 'GPL-2',
101
+ :description => 'GNU Public License v2.0',
102
+ :url => 'http://www.gnu.org/licenses/gpl-2.0.txt'
103
+
104
+ define 'GPL-3',
105
+ :description => 'GNU Public License v3.0',
106
+ :url => 'http://www.gnu.org/licenses/gpl-3.0.txt'
107
+
108
+ define 'LGPL-3',
109
+ :description => 'GNU Lesser General Public License v3.0',
110
+ :url => 'http://www.gnu.org/licenses/lgpl-3.0.txt'
83
111
 
84
112
  # The MIT Licence
85
- define 'MIT', :description => 'The MIT Licence', :url => 'http://www.opensource.org/licenses/mit-license.php'
113
+ define 'MIT',
114
+ :description => 'The MIT Licence',
115
+ :url => 'http://www.opensource.org/licenses/mit-license.php'
86
116
 
87
117
  end
88
118
  end
data/lib/ronin/os.rb CHANGED
@@ -23,7 +23,8 @@
23
23
 
24
24
  require 'ronin/model'
25
25
  require 'ronin/extensions/meta'
26
- require 'ronin/extensions/string'
26
+
27
+ require 'extlib'
27
28
 
28
29
  module Ronin
29
30
  class OS
@@ -63,7 +64,7 @@ module Ronin
63
64
  #
64
65
  def OS.define(name)
65
66
  name = name.to_s
66
- method_name = name.to_method_name
67
+ method_name = name.snake_case
67
68
 
68
69
  meta_def(method_name) do
69
70
  OS.new(:name => name)
@@ -24,6 +24,7 @@
24
24
  require 'ronin/platform/exceptions/extension_not_found'
25
25
  require 'ronin/platform/extension_cache'
26
26
  require 'ronin/platform/platform'
27
+ require 'ronin/static/finders'
27
28
 
28
29
  require 'contextify'
29
30
 
@@ -32,6 +33,7 @@ module Ronin
32
33
  class Extension
33
34
 
34
35
  include Contextify
36
+ include Static::Finders
35
37
 
36
38
  contextify :ronin_extension
37
39
 
@@ -41,6 +43,9 @@ module Ronin
41
43
  # Extension lib/ directory
42
44
  LIB_DIR = 'lib'
43
45
 
46
+ # Extension static/ directory
47
+ STATIC_DIR = 'static'
48
+
44
49
  # Name of extension
45
50
  attr_reader :name
46
51
 
@@ -242,150 +247,15 @@ module Ronin
242
247
  return self
243
248
  end
244
249
 
245
- #
246
- # Find the specified _path_ from within all similar extensions.
247
- # If a _block_ is given, it will be passed the full path if found.
248
- #
249
- # ext.find_paths('data/test')
250
- # # => [...]
251
- #
252
- # ext.find_paths('data/test') do |path|
253
- # puts Dir[File.join(path,'*')]
254
- # end
255
- #
256
- def find_paths(path,&block)
257
- matched_paths = []
258
-
259
- @paths.each do |ext_path|
260
- full_path = File.expand_path(File.join(ext_path,path))
261
-
262
- if File.exists?(full_path)
263
- block.call(full_path) if block
264
- matched_paths << full_path
265
- end
266
- end
267
-
268
- return matched_paths
269
- end
270
-
271
- #
272
- # Find the specified _path_ from within the first similar extensions.
273
- # If a _block_ is given, it will be passed the full path if found.
274
- #
275
- # ext.find_path('data/test')
276
- #
277
- # ext.find_path('data/test') do |path|
278
- # puts Dir[File.join(path,'*')]
279
- # end
280
- #
281
- def find_path(path,&block)
282
- find_paths(path) do |full_path|
283
- block.call(full_path) if block
284
- return full_path
285
- end
286
-
287
- return nil
288
- end
289
-
290
- #
291
- # Find the specified file _path_ from within the first similar extensions.
292
- # If a _block_ is given, it will be passed the full file path if
293
- # found.
294
- #
295
- # ext.find_file('data/test/file.xml')
296
- #
297
- # ext.find_file('data/test/file.xml') do |file|
298
- # Nokogiri::XML(open(file))
299
- # ...
300
- # end
301
- #
302
- def find_file(path,&block)
303
- find_paths(path) do |full_path|
304
- if File.file?(full_path)
305
- block.call(full_path) if block
306
- return full_path
307
- end
308
- end
309
- end
250
+ def static_paths(path,&block)
251
+ @paths.each do |dir|
252
+ static_dir = File.join(dir,STATIC_DIR)
253
+ next unless File.directory?(static_dir)
310
254
 
311
- #
312
- # Find the specified directory _path_ from within the first similar
313
- # extensions. If a _block_ is given, it will be passed the full
314
- # directory path if found.
315
- #
316
- # ext.find_directory('data/test')
317
- #
318
- # ext.find_directory('data/test') do |dir|
319
- # puts Dir[File.join(dir,'*')]
320
- # end
321
- #
322
- def find_dir(path,&block)
323
- find_paths(path) do |full_path|
324
- if File.directory?(full_path)
325
- block.call(full_path) if block
326
- return full_path
327
- end
328
- end
329
- end
330
-
331
- #
332
- # Find the paths that match the given pattern from within all similar
333
- # extensions. If a _block_ is given, it will be passed each matching
334
- # full path.
335
- #
336
- # ext.glob_paths('data/*') # => [...]
337
- #
338
- # ext.glob_paths('data/*') do |path|
339
- # puts path
340
- # end
341
- #
342
- def glob_paths(pattern,&block)
343
- full_paths = @paths.inject([]) do |paths,ext_path|
344
- paths + Dir[File.join(ext_path,pattern)]
345
- end
346
-
347
- full_paths.each(&block) if block
348
- return full_paths
349
- end
350
-
351
- #
352
- # Find the file paths that match the given pattern from within all
353
- # similar extensions. If a _block_ is given, it will be passed each
354
- # matching full file path.
355
- #
356
- # ext.glob_files('data/*.xml') # => [...]
357
- #
358
- # ext.glob_files('data/*.xml') do |file|
359
- # puts file
360
- # end
361
- #
362
- def glob_files(pattern,&block)
363
- full_paths = glob_paths(pattern).select do |path|
364
- File.file?(path)
365
- end
366
-
367
- full_paths.each(&block) if block
368
- return full_paths
369
- end
370
-
371
- #
372
- # Find the directory paths that match the given pattern from within
373
- # all similar extensions. If a _block_ is given, it will be passed
374
- # each matching full directory path.
375
- #
376
- # ext.glob_dirs('builds/*') # => [...]
377
- #
378
- # ext.glob_dirs('builds/*') do |dir|
379
- # puts dir
380
- # end
381
- #
382
- def glob_dirs(pattern,&block)
383
- full_paths = glob_paths(pattern).select do |path|
384
- File.directory?(path)
255
+ block.call(File.join(static_dir,path))
385
256
  end
386
257
 
387
- full_paths.each(&block) if block
388
- return full_paths
258
+ super(path,&block)
389
259
  end
390
260
 
391
261
  #
@@ -85,6 +85,17 @@ module Ronin
85
85
  end
86
86
  end
87
87
 
88
+ #
89
+ # Reloads the extensions within the extension cache.
90
+ #
91
+ def reload!
92
+ each do |name,ext|
93
+ ext.teardown!
94
+
95
+ self[name] = load_extension(name)
96
+ end
97
+ end
98
+
88
99
  end
89
100
  end
90
101
  end
@@ -24,23 +24,32 @@
24
24
  require 'ronin/platform/exceptions/extension_not_found'
25
25
  require 'ronin/platform/maintainer'
26
26
  require 'ronin/platform/extension'
27
+ require 'ronin/static/static'
27
28
 
28
29
  require 'repertoire'
29
30
  require 'nokogiri'
30
31
 
31
32
  module Ronin
32
33
  module Platform
33
- class Overlay < Repertoire::Repository
34
+ class Overlay
35
+
36
+ include Repertoire
34
37
 
35
38
  # Overlay metadata XML file name
36
39
  METADATA_FILE = 'ronin.xml'
37
40
 
38
- # Overlay lib directory
41
+ # Overlay lib/ directory
39
42
  LIB_DIR = 'lib'
40
43
 
44
+ # Overlay static/ directory
45
+ STATIC_DIR = 'static'
46
+
41
47
  # Overlay objects directory
42
48
  OBJECTS_DIR = 'objects'
43
49
 
50
+ # Reserved directories
51
+ RESERVED_DIRS = [LIB_DIR, STATIC_DIR, OBJECTS_DIR]
52
+
44
53
  # Local path to the overlay
45
54
  attr_reader :path
46
55
 
@@ -71,20 +80,26 @@ module Ronin
71
80
  # Description
72
81
  attr_reader :description
73
82
 
83
+ # The static directory
84
+ attr_reader :static_dir
85
+
74
86
  # The objects directory
75
87
  attr_reader :objects_dir
76
88
 
89
+ # Repository of the overlay
90
+ attr_reader :repository
91
+
77
92
  #
78
- # Creates a new Overlay object with the specified _path_, _media_type_
93
+ # Creates a new Overlay object with the specified _path_, _media_
79
94
  # and _uri_.
80
95
  #
81
- def initialize(path,media_type=nil,uri=nil,&block)
96
+ def initialize(path,media=nil,uri=nil,&block)
82
97
  @path = File.expand_path(path)
83
98
  @name = File.basename(@path)
99
+ @static_dir = File.join(@path,STATIC_DIR)
84
100
  @objects_dir = File.join(@path,OBJECTS_DIR)
85
101
  @uri = uri
86
-
87
- super(@path,Repertoire::Media.types[media_type])
102
+ @repository = Repository.new(@path,Media.types[media])
88
103
 
89
104
  initialize_metadata(&block)
90
105
  end
@@ -92,22 +107,18 @@ module Ronin
92
107
  #
93
108
  # Media type of the overlay.
94
109
  #
95
- def media_type
96
- if @media
97
- return @media.name
98
- else
99
- return nil
100
- end
110
+ def media
111
+ @repository.media_name
101
112
  end
102
113
 
103
114
  #
104
115
  # Returns the paths of all extensions within the overlay.
105
116
  #
106
117
  def extension_paths
107
- directories.reject do |dir|
118
+ @repository.directories.reject do |dir|
108
119
  name = File.basename(dir)
109
120
 
110
- (name == OBJECTS_DIR) || (name == LIB_DIR)
121
+ RESERVED_DIRS.include?(name)
111
122
  end
112
123
  end
113
124
 
@@ -154,10 +165,13 @@ module Ronin
154
165
  # <tt>$LOAD_PATH</tt>.
155
166
  #
156
167
  def activate!
168
+ # add the lib/ directories
157
169
  lib_dirs.each do |path|
158
170
  $LOAD_PATH << path unless $LOAD_PATH.include?(path)
159
171
  end
160
172
 
173
+ # add the static/ directory
174
+ Static.directory(@static_dir) if File.directory?(@static_dir)
161
175
  return true
162
176
  end
163
177
 
@@ -166,8 +180,9 @@ module Ronin
166
180
  # <tt>$LOAD_PATH</tt>.
167
181
  #
168
182
  def deactive!
169
- paths = lib_dirs
183
+ Static.static_dirs.reject! { |dir| dir == @static_dir }
170
184
 
185
+ paths = lib_dirs
171
186
  $LOAD_PATH.reject! { |path| paths.include?(path) }
172
187
  return true
173
188
  end
@@ -177,11 +192,11 @@ module Ronin
177
192
  # is given it will be called after the overlay has been updated.
178
193
  #
179
194
  def update(&block)
180
- if media_type
181
- Repertoire.update(:media => media_type, :path => @path, :uri => @uri)
195
+ if @repository.update(@uri)
196
+ initialize_metadata(&block)
182
197
  end
183
198
 
184
- return initialize_metadata(&block)
199
+ return self
185
200
  end
186
201
 
187
202
  #
@@ -190,7 +205,7 @@ module Ronin
190
205
  # has been uninstalled.
191
206
  #
192
207
  def uninstall(&block)
193
- Repertoire.delete(@path)
208
+ @repository.delete
194
209
 
195
210
  block.call(self) if block
196
211
  return self
@@ -228,11 +243,25 @@ module Ronin
228
243
  doc = Nokogiri::XML(open(metadata_path))
229
244
  overlay = doc.at('/ronin-overlay')
230
245
 
231
- @title = overlay.at('title').inner_text.strip
232
- @license = overlay.at('license').inner_text.strip
233
- @source = overlay.at('source').inner_text.strip
234
- @source_view = overlay.at('source-view').inner_text.strip
235
- @website = overlay.at('website').inner_text.strip
246
+ if (title_tag = overlay.at('title'))
247
+ @title = title_tag.inner_text.strip
248
+ end
249
+
250
+ if (license_tag = overlay.at('license'))
251
+ @license = license_tag.inner_text.strip
252
+ end
253
+
254
+ if (source_tag = overlay.at('source'))
255
+ @source = source_tag.inner_text.strip
256
+ end
257
+
258
+ if (source_view_tag = @source_view = overlay.at('source-view'))
259
+ @source_view = source_view_tag.inner_text.strip
260
+ end
261
+
262
+ if (website_tag = @website = overlay.at('website'))
263
+ @website = website_tag.inner_text.strip
264
+ end
236
265
 
237
266
  overlay.search('maintainers/maintainer').each do |maintainer|
238
267
  if (name = maintainer.at('name'))
@@ -246,7 +275,9 @@ module Ronin
246
275
  @maintainers << Maintainer.new(name,email)
247
276
  end
248
277
 
249
- @description = overlay.search('description').inner_text.strip
278
+ if (description_tag = overlay.at('description'))
279
+ @description = description_tag.inner_text.strip
280
+ end
250
281
  end
251
282
 
252
283
  block.call(self) if block