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
@@ -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">