smalruby-editor 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of smalruby-editor might be problematic. Click here for more details.

Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/blocks/hardware.js.coffee.erb +40 -3
  3. data/app/assets/stylesheets/toolbox.css.scss.erb +1 -6
  4. data/app/controllers/source_codes_controller.rb +5 -1
  5. data/app/models/concerns/ruby_to_block.rb +17 -360
  6. data/app/models/concerns/ruby_to_block/block.rb +97 -0
  7. data/app/models/concerns/ruby_to_block/block/base.rb +251 -0
  8. data/app/models/concerns/ruby_to_block/block/character.rb +42 -0
  9. data/app/models/concerns/ruby_to_block/block/character_event.rb +27 -0
  10. data/app/models/concerns/ruby_to_block/block/character_method_call.rb +29 -0
  11. data/app/models/concerns/ruby_to_block/block/character_new.rb +7 -0
  12. data/app/models/concerns/ruby_to_block/block/character_operation.rb +80 -0
  13. data/app/models/concerns/ruby_to_block/block/control_if.rb +45 -0
  14. data/app/models/concerns/ruby_to_block/block/control_loop.rb +19 -0
  15. data/app/models/concerns/ruby_to_block/block/control_sleep.rb +18 -0
  16. data/app/models/concerns/ruby_to_block/block/do.rb +24 -0
  17. data/app/models/concerns/ruby_to_block/block/else.rb +12 -0
  18. data/app/models/concerns/ruby_to_block/block/end.rb +26 -0
  19. data/app/models/concerns/ruby_to_block/block/events_on_click.rb +14 -0
  20. data/app/models/concerns/ruby_to_block/block/events_on_key_push_or_down.rb +17 -0
  21. data/app/models/concerns/ruby_to_block/block/events_on_start.rb +14 -0
  22. data/app/models/concerns/ruby_to_block/block/hardware_init_hardware.rb +14 -0
  23. data/app/models/concerns/ruby_to_block/block/hardware_led_off.rb +16 -0
  24. data/app/models/concerns/ruby_to_block/block/hardware_led_on.rb +16 -0
  25. data/app/models/concerns/ruby_to_block/block/hardware_on_sensor_change.rb +17 -0
  26. data/app/models/concerns/ruby_to_block/block/hardware_rgb_led_off.rb +18 -0
  27. data/app/models/concerns/ruby_to_block/block/hardware_rgb_led_on.rb +23 -0
  28. data/app/models/concerns/ruby_to_block/block/hardware_sensor_value.rb +23 -0
  29. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car.rb +26 -0
  30. data/app/models/concerns/ruby_to_block/block/looks_hide.rb +8 -0
  31. data/app/models/concerns/ruby_to_block/block/looks_say.rb +20 -0
  32. data/app/models/concerns/ruby_to_block/block/looks_show.rb +8 -0
  33. data/app/models/concerns/ruby_to_block/block/looks_vanish.rb +8 -0
  34. data/app/models/concerns/ruby_to_block/block/math_number.rb +14 -0
  35. data/app/models/concerns/ruby_to_block/block/motion_change_x_by.rb +20 -0
  36. data/app/models/concerns/ruby_to_block/block/motion_change_y_by.rb +20 -0
  37. data/app/models/concerns/ruby_to_block/block/motion_move.rb +15 -0
  38. data/app/models/concerns/ruby_to_block/block/motion_point_towards_character.rb +24 -0
  39. data/app/models/concerns/ruby_to_block/block/motion_point_towards_mouse.rb +9 -0
  40. data/app/models/concerns/ruby_to_block/block/motion_reach_wall.rb +24 -0
  41. data/app/models/concerns/ruby_to_block/block/motion_rotate_left.rb +20 -0
  42. data/app/models/concerns/ruby_to_block/block/motion_rotate_right.rb +20 -0
  43. data/app/models/concerns/ruby_to_block/block/motion_self_angle.rb +23 -0
  44. data/app/models/concerns/ruby_to_block/block/motion_self_x.rb +23 -0
  45. data/app/models/concerns/ruby_to_block/block/motion_self_y.rb +23 -0
  46. data/app/models/concerns/ruby_to_block/block/motion_set_angle.rb +15 -0
  47. data/app/models/concerns/ruby_to_block/block/motion_set_x.rb +38 -0
  48. data/app/models/concerns/ruby_to_block/block/motion_set_y.rb +15 -0
  49. data/app/models/concerns/ruby_to_block/block/motion_turn.rb +8 -0
  50. data/app/models/concerns/ruby_to_block/block/motion_turn_if_reach_wall.rb +8 -0
  51. data/app/models/concerns/ruby_to_block/block/null.rb +17 -0
  52. data/app/models/concerns/ruby_to_block/block/operators_compare.rb +36 -0
  53. data/app/models/concerns/ruby_to_block/block/operators_false.rb +8 -0
  54. data/app/models/concerns/ruby_to_block/block/operators_true.rb +8 -0
  55. data/app/models/concerns/ruby_to_block/block/require_smalruby.rb +7 -0
  56. data/app/models/concerns/ruby_to_block/block/ruby_comment.rb +16 -0
  57. data/app/models/concerns/ruby_to_block/block/ruby_expression.rb +14 -0
  58. data/app/models/concerns/ruby_to_block/block/ruby_statement.rb +23 -0
  59. data/app/models/concerns/ruby_to_block/block/sensing_hit.rb +23 -0
  60. data/app/models/concerns/ruby_to_block/block/sound_play.rb +15 -0
  61. data/app/models/concerns/ruby_to_block/block/sound_preset_sounds.rb +31 -0
  62. data/app/models/concerns/ruby_to_block/block/text.rb +15 -0
  63. data/app/models/concerns/ruby_to_block/block/value.rb +12 -0
  64. data/app/models/concerns/ruby_to_block/context.rb +97 -0
  65. data/app/models/concerns/ruby_to_block/formatter.rb +26 -0
  66. data/app/models/source_code.rb +3 -1
  67. data/app/views/editor/_toolbox.html.haml +16 -0
  68. data/lib/smalruby_editor/version.rb +3 -3
  69. data/smalruby-editor.gemspec +1 -1
  70. data/spec/acceptance/block_mode/blocks/hardware/two_wheel_drive_car.feature +69 -0
  71. data/spec/acceptance/ruby_mode/translate.feature +1 -1
  72. data/spec/controllers/source_codes_controller_spec.rb +14 -11
  73. data/spec/models/concerns/ruby_to_block/block/character_method_call_spec.rb +175 -0
  74. data/spec/models/concerns/ruby_to_block/block/control_if_spec.rb +75 -0
  75. data/spec/models/concerns/ruby_to_block/block/control_loop_spec.rb +68 -0
  76. data/spec/models/concerns/ruby_to_block/block/events_on_start_spec.rb +120 -0
  77. data/spec/models/concerns/ruby_to_block/block/hardware_spec.rb +120 -0
  78. data/spec/models/concerns/ruby_to_block/block/looks_say_spec.rb +79 -0
  79. data/spec/models/concerns/ruby_to_block/block/looks_spec.rb +74 -0
  80. data/spec/models/concerns/ruby_to_block/block/motion_move_spec.rb +63 -0
  81. data/spec/models/concerns/ruby_to_block/block/motion_reach_wall_spec.rb +67 -0
  82. data/spec/models/concerns/ruby_to_block/block/motion_spec.rb +392 -0
  83. data/spec/models/concerns/ruby_to_block/block/motion_turn_spec.rb +54 -0
  84. data/spec/models/concerns/ruby_to_block/block/require_smalruby_spec.rb +39 -0
  85. data/spec/models/concerns/ruby_to_block/block/ruby_comment_spec.rb +55 -0
  86. data/spec/models/concerns/ruby_to_block/block/ruby_statement_spec.rb +113 -0
  87. data/spec/models/concerns/ruby_to_block/block/shared/block_examples.rb +44 -0
  88. data/spec/models/concerns/ruby_to_block/block/sound_spec.rb +46 -0
  89. data/spec/models/concerns/ruby_to_block/block_spec.rb +49 -0
  90. data/spec/models/concerns/ruby_to_block_spec.rb +421 -217
  91. data/spec/support/ruby_to_block.rb +10 -0
  92. metadata +108 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 531341c4a66cfc4403c5920b096a7bc9da6c2d93
4
- data.tar.gz: e6110e9a3814bdf0388d7621cffa81f39d5b508b
3
+ metadata.gz: 481219ecbb11af4414b736a08666df8c1d4b2a98
4
+ data.tar.gz: c0158c87c4892af0db1130770e55d3f8966f6a73
5
5
  SHA512:
6
- metadata.gz: ece39fa8e6d0e898c34a2c338b8e91123cb1cc814410370921125a06af034e0624b68599f912be686c5057ab67282f061b92de9d46b9d17c2321a29ee2a05f8a
7
- data.tar.gz: 2ea31229e0a0f5a411946c24c347c9a7c5d290cd4b5c5ac28fa70db4609fb67486a419d0404d8c1efdba339c60a879202ee8bddc4be69e6317dc5b1ebe808d6e
6
+ metadata.gz: 8eeaa4d664ad6fa1b258798787749a831b386d66ee40fa7e323d19686352c2b9f96e11f4fee0ed300b54dc59177e69c3103ce9a408a0bddaf8351b86b301561a
7
+ data.tar.gz: 4ace3c4984b24bc8f1996e11f6cbcd5de2aea320d00f5ce216b0c6ed7e47ec3128ee99b8cf396902249e0dca0b283976072397125adf01f88dc6fff4840ce7e2
@@ -235,13 +235,50 @@ Blockly.Blocks['<%= n %>'] =
235
235
  @setTooltip('')
236
236
 
237
237
  Blockly.Ruby['<%= n %>'] = (block) ->
238
- pin = @getFieldValue('PIN') #p sensor("A0").value
239
- #p sensor("A0").value.class
240
- #p(sensor("A0").value / 6)
238
+ pin = @getFieldValue('PIN')
241
239
 
242
240
  pos = Blockly.Ruby.valueToCode(@, 'POS', Blockly.Ruby.ORDER_FUNCTION_CALL) || '5'
243
241
  Blockly.Ruby.characterMethodCall_("servo(#{Blockly.Ruby.quote_(pin)}).position = #{pos}")
244
242
 
243
+ # 「車」サブジャンル
244
+
245
+ # 「2WD車[▼ピン]を進める」ブロック
246
+ # 「2WD車[▼ピン]をバックさせる」ブロック
247
+ # 「2WD車[▼ピン]を左に曲げる」ブロック
248
+ # 「2WD車[▼ピン]を右に曲げる」ブロック
249
+ # 「2WD車[▼ピン]を止める」ブロック
250
+ <%
251
+ [
252
+ ['forward', '進める'],
253
+ ['backward', 'バックさせる'],
254
+ ['turn_left', '左に曲げる'],
255
+ ['turn_right', '右に曲げる'],
256
+ ['stop', '止める'],
257
+ ].each do |method, label|
258
+ n = "#{category}_two_wheel_drive_car_#{method}"
259
+ %>
260
+
261
+ Blockly.Blocks['<%= n %>'] =
262
+ init: ()->
263
+ dropdown = (["D#{n}", "D#{n}"] for n in [2..10])
264
+
265
+ @setHelpUrl('')
266
+ @setColour(<%= color %>)
267
+ @appendDummyInput()
268
+ .appendField('2WD車')
269
+ .appendField(new Blockly.FieldDropdown(dropdown), 'PIN')
270
+ .appendField('を<%= label %>')
271
+ @setInputsInline(true)
272
+ @setPreviousStatement(true)
273
+ @setNextStatement(true)
274
+ @setTooltip('')
275
+
276
+ Blockly.Ruby['<%= n %>'] = (block) ->
277
+ pin = @getFieldValue('PIN')
278
+
279
+ Blockly.Ruby.characterMethodCall_("two_wheel_drive_car(#{Blockly.Ruby.quote_(pin)}).<%= method %>")
280
+ <% end %>
281
+
245
282
  # 「ボタン」サブジャンル
246
283
 
247
284
  # 条件:ボタン[▼]を押している
@@ -42,10 +42,9 @@
42
42
  208
43
43
  208
44
44
  208
45
+ 208
45
46
  ).map(&:to_i)
46
47
 
47
- ruby_genre_index = hues.index(340) + 1
48
-
49
48
  colors = hues.map { |h|
50
49
  [hsv_to_rgb(h, 100, 80), hsv_to_rgb(h, 100, 100)]
51
50
  }
@@ -55,10 +54,6 @@
55
54
  %>
56
55
 
57
56
  #\:<%= ids[index] %> {
58
- <% if index == ruby_genre_index %>
59
- display: none;
60
-
61
- <% end %>
62
57
  .blocklyTreeRow {
63
58
  padding-top: 0.25em;
64
59
  padding-bottom: 0.25em;
@@ -61,7 +61,11 @@ class SourceCodesController < ApplicationController
61
61
  source_code = SourceCode.new(source_code_params)
62
62
  render text: source_code.to_blocks
63
63
  rescue
64
- head :bad_request
64
+ if Rails.env == 'development'
65
+ raise
66
+ else
67
+ head :bad_request
68
+ end
65
69
  end
66
70
 
67
71
  private
@@ -1,391 +1,48 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- # rubocop:disable all
3
+ require_relative 'ruby_to_block/block'
4
+ require_relative 'ruby_to_block/context'
5
+ require_relative 'ruby_to_block/formatter'
4
6
 
5
7
  # Rubyのソースコードをブロックに変換するモジュール
6
8
  module RubyToBlock
7
9
  extend ActiveSupport::Concern
8
10
 
9
- SUCCESS_DATA_MOCK = <<-EOS.strip_heredoc
10
- require "smalruby"
11
-
12
- car1 = Character.new(costume: "car1.png", x: 0, y: 0, angle: 0)
13
-
14
- car1.on(:start) do
15
- loop do
16
- move(10)
17
- turn_if_reach_wall
18
- end
19
- end
20
- EOS
21
-
22
- SUCCESS_XML_MOCK = <<-XML.strip_heredoc
23
- <xml xmlns="http://www.w3.org/1999/xhtml">
24
- <character name="car1" x="0" y="0" angle="0" costumes="car1.png" />
25
- <block type="character_new" x="4" y="4">
26
- <field name="NAME">car1</field>
27
- <statement name="DO">
28
- <block type="events_on_start">
29
- <statement name="DO">
30
- <block type="control_loop">
31
- <statement name="DO">
32
- <block type="motion_move" inline="true">
33
- <value name="STEP">
34
- <block type="math_number">
35
- <field name="NUM">10</field>
36
- </block>
37
- </value>
38
- <next>
39
- <block type="motion_turn_if_reach_wall" />
40
- </next>
41
- </block>
42
- </statement>
43
- </block>
44
- </statement>
45
- </block>
46
- </statement>
47
- </block>
48
- </xml>
49
- XML
50
-
51
11
  # XML形式のブロックに変換する
52
12
  def to_blocks
53
13
  fail if data == '__FAIL__'
54
- return SUCCESS_XML_MOCK if data == SUCCESS_DATA_MOCK
55
14
 
56
- characters = {}
57
- character_stack = []
58
- receiver_stack = []
59
- statement_stack = []
60
- blocks = []
61
- current_block = nil
62
- lines = data.lines
63
- while (line = lines.shift)
15
+ context = Context.new(data.lines)
16
+ while (line = context.next_line)
64
17
  line.chomp!
65
18
  next if line.strip.empty?
19
+ md = Block.statement_regexp.match(line)
20
+ next if Block.process_match_data(md, context)
21
+ Block.process_match_data(md, context, 'ruby_statement')
22
+ end
66
23
 
67
- md = STATEMENT_REGEXP.match(line)
68
-
69
- unless md
70
- block = Block.new('ruby_statement', fields: { STATEMENT: line })
71
- if current_block # TODO: リファクタリング
72
- current_block.sibling = block
73
- else
74
- blocks.push(block)
75
- end
76
- current_block = block
77
-
78
- next
79
- end
80
-
81
- next if md[:require_smalruby]
82
-
83
- if (s = md[:character])
84
- md2 = /#{CHARACTER_RE}/.match(s)
85
- name = md2[1]
86
-
87
- characters[name] = Character.new(name: name, costumes: [md2[2]],
88
- x: md2[3], y: md2[4], angle: md2[5])
89
- next
90
- end
91
-
92
- if (s = md[:events_on_start])
93
- md2 = /#{EVENTS_ON_START_RE}/.match(s)
94
- name = md2[1] ? md2[1] : receiver_stack.last.name
95
- c = characters[name]
96
- character_stack.push(c)
97
-
98
- do_block = Block.new('null')
99
- events_on_start_block = Block.new('events_on_start', statements: { DO: do_block })
100
- if current_block && current_block.type == 'character_new' &&
101
- current_block[:NAME] == name
102
- current_block.add_statement(:DO, events_on_start_block)
103
- character_new_block = current_block
104
- else
105
- if c == receiver_stack.last
106
- current_block.sibling = events_on_start_block
107
- character_new_block = current_block.parent
108
- else
109
- character_new_block =
110
- Block.new('character_new',
111
- fields: { NAME: name }, statements: { DO: events_on_start_block })
112
- if current_block
113
- if current_block.type == 'character_new'
114
- blocks.push(character_new_block)
115
- else
116
- current_block.sibling = character_new_block
117
- end
118
- else
119
- blocks.push(character_new_block)
120
- end
121
- end
122
- end
123
- statement_stack.push([:events_on_start, character_new_block])
124
-
125
- receiver_stack.push(c)
126
-
127
- current_block = do_block
128
-
129
- next
130
- end
131
-
132
- if md[:end]
133
- ends_num = lines.select { |l|
134
- md2 = STATEMENT_REGEXP.match(l)
135
- md2 && md2[:end]
136
- }.length + 1
137
- ends_num -= lines.select { |l|
138
- md2 = STATEMENT_REGEXP.match(l)
139
- md2 && (md2[:events_on_start])
140
- }.length
141
- if (ss = statement_stack.last) &&
142
- ends_num <= statement_stack.length
143
- case ss.first
144
- when :events_on_start
145
- current_block = ss[1]
146
-
147
- receiver_stack.pop
148
- character_stack.pop
149
- statement_stack.pop
150
- else
151
- # TODO
152
- end
153
- else
154
- block = Block.new('ruby_statement', fields: { STATEMENT: line })
155
- if current_block # TODO: リファクタリング
156
- current_block.sibling = block
157
- else
158
- blocks.push(block)
159
- end
160
- current_block = block
161
- end
24
+ make_xml(context)
25
+ end
162
26
 
163
- next
164
- end
165
- end
27
+ private
166
28
 
167
- return '' if characters.empty? && blocks.empty?
29
+ def make_xml(context)
30
+ return '' if context[:characters].empty? && context[:blocks].empty?
168
31
 
169
32
  xml = REXML::Document.new('<xml xmlns="http://www.w3.org/1999/xhtml" />',
170
33
  attribute_quote: :quote,
171
34
  respect_whitespace: :all)
172
- characters.values.each do |c|
35
+ context[:characters].values.each do |c|
173
36
  c.to_xml(xml.root)
174
37
  end
175
- blocks.each do |b|
38
+ context[:blocks].each do |b|
176
39
  b.to_xml(xml.root)
177
40
  end
178
41
 
179
42
  output = StringIO.new
180
- formatter = REXML::Formatters::Pretty.new(2, true)
181
- formatter.compact = true
182
- # HACK: 行頭、行末などのスペースが1つになってしまうのを修正している
183
- def formatter.write_text( node, output )
184
- s = node.to_s()
185
- s.gsub!(/\s/,' ')
186
- if !node.is_a?(REXML::Text) ||
187
- node.is_a?(REXML::Text) && !node.parent.whitespace()
188
- s.squeeze!(" ")
189
- end
190
- s = wrap(s, @width - @level)
191
- s = indent_text(s, @level, " ", true)
192
- output << (' '*@level + s)
193
- end
43
+ formatter = Formatter.new
194
44
  formatter.write(xml, output)
195
45
 
196
46
  output.string + "\n"
197
47
  end
198
-
199
- private
200
-
201
- # require "smalruby"
202
- REQUIRE_SMALRUBY_RE = '^require\ "smalruby"$'
203
-
204
- # car1 = Character.new(costume: "car1.png", x: 0, y: 0, angle: 0)
205
- CHARACTER_RE =
206
- '^\s*(\S+)\ =\ Character\.new\(costume:\ "([^"]+)",\ x:\ (\d+),\ y:\ (\d+),\ angle:\ (\d+)\)$'
207
-
208
- EVENTS_ON_START_RE = '^\s*(?:(\S+)\.)?on\(:start\)\ do$'
209
-
210
- END_RE = '^\s*end$'
211
-
212
- STATEMENT_REGEXP = %r{
213
- (?<require_smalruby>#{REQUIRE_SMALRUBY_RE})
214
- |
215
- (?<character>#{CHARACTER_RE})
216
- |
217
- (?<events_on_start>#{EVENTS_ON_START_RE})
218
- |
219
- (?<end>#{END_RE})
220
- }x
221
-
222
- EXPRESSION_REGEXP = %r{}x
223
- LITERAL_REGEXP = %r{}x
224
-
225
- # ソースコードに含まれるキャラクターを表現するクラス
226
- class Character
227
- attr_accessor :name
228
- attr_accessor :costumes
229
- attr_accessor :x
230
- attr_accessor :y
231
- attr_accessor :angle
232
-
233
- def initialize(options)
234
- @name = options[:name]
235
- @costumes = options[:costumes]
236
- @x = options[:x]
237
- @y = options[:y]
238
- @angle = options[:angle]
239
- end
240
-
241
- def to_xml(parent)
242
- parent.add_element('character',
243
- 'name' => @name,
244
- 'x' => @x, 'y' => @y, 'angle' => @angle,
245
- 'costumes' => @costumes.join(','))
246
- end
247
- end
248
-
249
- # ブロック群を表現するモジュール
250
- module Block
251
- # ブロックのインスタンスを生成する
252
- def self.new(type, *args)
253
- const_get(type.camelize).new(*args)
254
- end
255
-
256
- # すべてのブロックのベースクラス
257
- class Base
258
- attr_accessor :parent
259
- attr_accessor :sibling
260
- attr_accessor :fields
261
- attr_accessor :values
262
- attr_accessor :statements
263
-
264
- def initialize(options = {})
265
- @fields = options[:fields] || {}
266
- @values = options[:values] || {}
267
- @statements = options[:statements] || {}
268
-
269
- if @statements.length > 0
270
- @statements.values.each do |s|
271
- s.parent = self
272
- end
273
- end
274
- end
275
-
276
- def to_xml(parent)
277
- e = parent.add_element('block', 'type' => type)
278
- e.add_attribute('inline', 'true') if inline?
279
- fields_to_xml(e)
280
- values_to_xml(e)
281
- statements_to_xml(e)
282
- sibling_to_xml(e)
283
- e
284
- end
285
-
286
- def type
287
- @type ||= self.class.name.sub('RubyToBlock::Block::', '').underscore
288
- end
289
-
290
- def inline?
291
- false
292
- end
293
-
294
- def null?
295
- false
296
- end
297
-
298
- def [](name)
299
- @fields[name]
300
- end
301
-
302
- def add_statement(name, block)
303
- b = @statements[name]
304
- b = b.sibling while b.sibling
305
- b.sibling = block
306
- end
307
-
308
- def sibling=(block)
309
- block.parent = self.parent
310
- @sibling = block
311
- end
312
-
313
- def indent?
314
- false
315
- end
316
-
317
- def indent_level
318
- b = self
319
- level = 0
320
- while b.parent
321
- level += 1 if b.indent?
322
- b = b.parent
323
- end
324
- level
325
- end
326
-
327
- private
328
-
329
- def fields_to_xml(parent)
330
- @fields.each do |k, v|
331
- e = parent.add_element('field', 'name' => k.to_s)
332
- if v.is_a?(String)
333
- e.text = v
334
- else
335
- # TODO
336
- end
337
- end
338
- end
339
-
340
- def values_to_xml(parent)
341
- @values.each do |k, v|
342
- # TODO
343
- end
344
- end
345
-
346
- def statements_to_xml(parent)
347
- @statements.each do |k, v|
348
- next if v.null?
349
- e = parent.add_element('statement', 'name' => k.to_s)
350
- v.to_xml(e)
351
- end
352
- end
353
-
354
- def sibling_to_xml(parent)
355
- return nil unless @sibling
356
-
357
- e = parent.add_element('next')
358
- @sibling.to_xml(e)
359
- end
360
- end
361
-
362
- class Null < Base
363
- def to_xml(parent)
364
- return nil unless @sibling
365
-
366
- @sibling.to_xml(parent)
367
- end
368
-
369
- def null?
370
- !@sibling
371
- end
372
- end
373
-
374
- class CharacterNew < Base; end
375
-
376
- class RubyStatement < Base
377
- def parent=(block)
378
- @parent = block
379
- @original_statement ||= @fields[:STATEMENT]
380
- @fields[:STATEMENT] =
381
- @original_statement.sub(/^ {0,#{indent_level * 2}}/, '')
382
- end
383
- end
384
-
385
- class EventsOnStart < Base
386
- def indent?
387
- true
388
- end
389
- end
390
- end
391
48
  end