smalruby-editor 0.1.6 → 0.1.7

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 (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
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class OperatorsFalse < Value
5
+ blocknize '^\s*false\s*$', value: true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class OperatorsTrue < Value
5
+ blocknize '^\s*true\s*$', value: true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class RequireSmalruby < Base
4
+ blocknize '^\s*require\s*"smalruby"\s*$', statement: true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class RubyComment < Base
5
+ blocknize '^\s*\#\ (.*)$', statement: true
6
+
7
+ def self.process_match_data(md, context)
8
+ md2 = regexp.match(md[type])
9
+ block = new(fields: { COMMENT: md2[1] })
10
+ context.add_block(block)
11
+
12
+ true
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class RubyExpression < Value
5
+ blocknize '^.*$', value: true, priority: -Float::INFINITY
6
+
7
+ def self.process_match_data(md, context)
8
+ context.add_value(new(fields: { EXP: md.string }))
9
+
10
+ true
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class RubyStatement < Base
4
+ blocknize '^.*$', statement: true, priority: -Float::INFINITY
5
+
6
+ def self.process_match_data(md, context)
7
+ block = new(fields: { STATEMENT: md.string })
8
+ context.add_block(block)
9
+
10
+ true
11
+ end
12
+
13
+ private
14
+
15
+ def fields_to_xml(e)
16
+ @fields[:STATEMENT] =
17
+ @fields[:STATEMENT].sub(/^ {0,#{indent_level * 2}}/, '')
18
+
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class SensingHit < Value
5
+ blocknize '^\s*hit\?\(([^)]+)\)\s*$', value: true
6
+
7
+ def self.process_match_data(md, context)
8
+ return false unless context.receiver
9
+
10
+ md2 = regexp.match(md[type])
11
+ name = md2[1]
12
+ name.strip!
13
+ c = context.characters[name]
14
+
15
+ return false unless c
16
+
17
+ context.add_value(new(fields: { CHAR: name }))
18
+
19
+ true
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class SoundPlay < CharacterMethodCall
5
+ blocknize '^\s*' + CHAR_RE + 'play\(name:\s*(.+)\)\s*$',
6
+ statement: true, inline: true
7
+
8
+ def self.process_match_data(md, context)
9
+ md2 = regexp.match(md[type])
10
+ add_character_method_call_block(context, md2[1], new, NAME: md2[2])
11
+ true
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class SoundPresetSounds < Value
5
+ blocknize '^\s*"([^"]*?\.wav)"\s*$', value: true, priority: 1
6
+
7
+ # TODO: 自動生成する
8
+ SOUNDS = %w(
9
+ piano_do.wav
10
+ piano_re.wav
11
+ piano_mi.wav
12
+ piano_fa.wav
13
+ piano_so.wav
14
+ piano_ra.wav
15
+ piano_si.wav
16
+ piano_do_2.wav
17
+ )
18
+
19
+ def self.process_match_data(md, context)
20
+ md2 = regexp.match(md[type])
21
+ if SOUNDS.include?(md2[1])
22
+ context.add_value(new(fields: { NAME: md2[1] }))
23
+ else
24
+ context.add_value(Text.new(fields: { TEXT: md2[1] }))
25
+ end
26
+
27
+ true
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class Text < Value
5
+ blocknize '^\s*"([^"]*)"\s*$', value: true
6
+
7
+ def self.process_match_data(md, context)
8
+ md2 = regexp.match(md[type])
9
+ context.add_value(new(fields: { TEXT: md2[1] }))
10
+
11
+ true
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class Value < Base
5
+ def self.process_match_data(md, context)
6
+ context.add_value(new)
7
+
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,97 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module RubyToBlock
4
+ # ソースコード解析の状態を表現するクラス
5
+ class Context
6
+ attr_accessor :current_line
7
+ attr_accessor :lines
8
+ attr_accessor :characters
9
+ attr_accessor :character_stack
10
+ attr_accessor :receiver_stack
11
+ attr_accessor :statement_stack
12
+ attr_accessor :value_name_stack
13
+ attr_accessor :blocks
14
+ attr_accessor :current_block
15
+
16
+ def initialize(lines)
17
+ @lines = lines
18
+ @characters = {}
19
+ @character_stack = []
20
+ @receiver_stack = []
21
+ @statement_stack = []
22
+ @value_name_stack = []
23
+ @blocks = []
24
+ @current_block = nil
25
+ end
26
+
27
+ # 次の行に移動して、改行を含むその行の文字列を返す
28
+ #
29
+ # @return [String] 改行を含む次の行の文字列
30
+ def next_line
31
+ self.current_line = lines.shift
32
+ end
33
+
34
+ # 次の行を参照する
35
+ #
36
+ # @return [String] 次の行の文字列
37
+ def look_next_line
38
+ lines.first
39
+ end
40
+
41
+ def add_block(block)
42
+ if current_block
43
+ # HACK: コメントは下の行に関係することが多いため対象外としている
44
+ if current_block.type == 'character_new' &&
45
+ block.type != 'character_new' && block.type != 'ruby_comment'
46
+ current_block.add_statement(:DO, block)
47
+ block = current_block
48
+ else
49
+ current_block.sibling = block
50
+ end
51
+ else
52
+ blocks.push(block)
53
+ end
54
+ self.current_block = block
55
+ self
56
+ end
57
+
58
+ def add_value(block)
59
+ fail unless current_block || value_name
60
+
61
+ current_block.add_value(value_name, block)
62
+ self
63
+ end
64
+
65
+ def [](symbol)
66
+ send(symbol)
67
+ end
68
+
69
+ def []=(symbol, val)
70
+ send("#{symbol}=", val)
71
+ end
72
+
73
+ def receiver
74
+ @receiver_stack.last
75
+ end
76
+
77
+ def character
78
+ @character_stack.last
79
+ end
80
+
81
+ def statement
82
+ @statement_stack.last
83
+ end
84
+
85
+ def statement_type
86
+ statement.first
87
+ end
88
+
89
+ def statement_block
90
+ statement[1]
91
+ end
92
+
93
+ def value_name
94
+ @value_name_stack.last
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module RubyToBlock
4
+ # XMLをフォーマットするクラス
5
+ #
6
+ # REXML::Formatters::Prettyでは行頭、行末などのスペースが1つになって
7
+ # しまうため、このクラスではそれらを修正している
8
+ class Formatter < REXML::Formatters::Pretty
9
+ def initialize
10
+ super(2, true)
11
+ self.compact = true
12
+ end
13
+
14
+ def write_text(node, output)
15
+ s = node.to_s
16
+ s.gsub!(/\s/, ' ')
17
+ if !node.is_a?(REXML::Text) ||
18
+ node.is_a?(REXML::Text) && !node.parent.whitespace
19
+ s.squeeze!(' ')
20
+ end
21
+ s = wrap(s, @width - @level)
22
+ s = indent_text(s, @level, ' ', true)
23
+ output << (' ' * @level + s)
24
+ end
25
+ end
26
+ end
@@ -4,7 +4,9 @@ require 'tempfile'
4
4
  require 'open3'
5
5
  require 'digest/sha2'
6
6
  require 'bundler'
7
- require_relative 'concerns/ruby_to_block'
7
+ silence_warnings do
8
+ require_relative 'concerns/ruby_to_block'
9
+ end
8
10
 
9
11
  # ソースコードを表現するモデル
10
12
  class SourceCode < ActiveRecord::Base
@@ -369,6 +369,22 @@
369
369
  -# %block{:type => "#{category}_servo_set_position"}
370
370
  -# = toolbox_number_value('POS', 90)
371
371
 
372
+ %category{:name => '車'}
373
+ -# 「2WD車[▼ピン]を進める」ブロック
374
+ %block{:type => "#{category}_two_wheel_drive_car_forward"}
375
+
376
+ -# 「2WD車[▼ピン]をバックさせる」ブロック
377
+ %block{:type => "#{category}_two_wheel_drive_car_backward"}
378
+
379
+ -# 「2WD車[▼ピン]を左に曲げる」ブロック
380
+ %block{:type => "#{category}_two_wheel_drive_car_turn_left"}
381
+
382
+ -# 「2WD車[▼ピン]を右に曲げる」ブロック
383
+ %block{:type => "#{category}_two_wheel_drive_car_turn_right"}
384
+
385
+ -# 「2WD車[▼ピン]を止める」ブロック
386
+ %block{:type => "#{category}_two_wheel_drive_car_stop"}
387
+
372
388
  -#%category{:name => 'ボタン'}
373
389
  -# -# 条件:ボタン[▼]を押している
374
390
  -# %block{:type => "#{category}_button_down"}
@@ -1,3 +1,3 @@
1
- module SmalrubyEditor
2
- VERSION = '0.1.6'
3
- end
1
+ module SmalrubyEditor
2
+ VERSION = '0.1.7'
3
+ end
@@ -68,7 +68,7 @@ Gem::Specification.new do |spec|
68
68
  ['launchy'],
69
69
  ['mime-types', '~> 1.16'],
70
70
  ['haml-rails'],
71
- ['smalruby'],
71
+ ['smalruby', '~> 0.0.15'],
72
72
  ]
73
73
  runtime_dependencies << ['therubyracer'] unless is_windows
74
74
  runtime_dependencies.each do |args|
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+ # language: ja
3
+ @javascript
4
+ 機能: hardware_two_wheel_drive_car_{forward,backward,turn_left,turn_right,stop} - 「2WD車[▼ピン]を{進める,バックさせる,左に曲げる,右に曲げる,止める}」ブロック
5
+ 背景:
6
+ 前提 "ブロック" タブを表示する
7
+ かつ 次のキャラクターを追加する:
8
+ | name | costumes | x | y | angle |
9
+ | car1 | car1.png | 0 | 0 | 0 |
10
+
11
+ シナリオテンプレート: ブロックのみ、キャラクターとブロック、キャラクターとイベントとブロックをそれぞれ配置する
12
+ # ブロックのみ配置する
13
+ もし 次のブロック("hardware_two_wheel_drive_car_<ブロック名のサフィックス>")を配置する:
14
+ """
15
+ %block{:type => "hardware_two_wheel_drive_car_<ブロック名のサフィックス>", :x => "0", :y => "0"}
16
+ %field{:name => "PIN"}<
17
+ D2
18
+ """
19
+ かつ ブロックからソースコードを生成する
20
+
21
+ ならば テキストエディタのプログラムは "" であること
22
+
23
+ # キャラクターとブロックを配置する
24
+ もし 次のブロック("hardware_two_wheel_drive_car_<ブロック名のサフィックス>")を配置する:
25
+ """
26
+ %block{:type => "character_new", :x => "21", :y => "15"}
27
+ %field{:name => "NAME"}<
28
+ car1
29
+ %statement{:name => "DO"}
30
+ %block{:type => "hardware_two_wheel_drive_car_<ブロック名のサフィックス>", :x => "0", :y => "0"}
31
+ %field{:name => "PIN"}<
32
+ D2
33
+ """
34
+ かつ ブロックからソースコードを生成する
35
+
36
+ ならば テキストエディタのプログラムは以下を含むこと:
37
+ """
38
+ car1.two_wheel_drive_car("D2").<ブロック名のサフィックス>
39
+ """
40
+
41
+ # キャラクターとイベントとブロックを配置する
42
+ もし 次のブロック("hardware_two_wheel_drive_car_<ブロック名のサフィックス>")を配置する:
43
+ """
44
+ %block{:type => "character_new", :x => "21", :y => "15"}
45
+ %field{:name => "NAME"}<
46
+ car1
47
+ %statement{:name => "DO"}
48
+ %block{:type => "events_on_start"}
49
+ %statement{:name => "DO"}
50
+ %block{:type => "hardware_two_wheel_drive_car_<ブロック名のサフィックス>", :x => "0", :y => "0"}
51
+ %field{:name => "PIN"}<
52
+ D2
53
+ """
54
+ かつ ブロックからソースコードを生成する
55
+
56
+ ならば テキストエディタのプログラムは以下を含むこと:
57
+ """
58
+ car1.on(:start) do
59
+ two_wheel_drive_car("D2").<ブロック名のサフィックス>
60
+ end
61
+ """
62
+
63
+ 例:
64
+ | ブロック名のサフィックス |
65
+ | forward |
66
+ | backward |
67
+ | turn_left |
68
+ | turn_right |
69
+ | stop |
@@ -29,7 +29,7 @@
29
29
  """
30
30
  <xml>
31
31
  <character x="0" y="0" name="car1" costumes="car1.png" angle="0"></character>
32
- <block type="character_new" x="4" y="4">
32
+ <block type="character_new" x="0" y="0">
33
33
  <field name="NAME">car1</field>
34
34
  <statement name="DO">
35
35
  <block type="events_on_start">