smalruby-editor 0.1.20 → 0.1.21

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/app/assets/javascripts/blocks/character.js.coffee.erb +3 -10
  4. data/app/assets/javascripts/blocks/control.js.coffee.erb +2 -1
  5. data/app/assets/javascripts/blocks/data.js.coffee.erb +2 -1
  6. data/app/assets/javascripts/blocks/etc.js.coffee.erb +2 -1
  7. data/app/assets/javascripts/blocks/events.js.coffee.erb +5 -4
  8. data/app/assets/javascripts/blocks/field_character.js.coffee.erb +9 -0
  9. data/app/assets/javascripts/blocks/hardware.js.coffee.erb +171 -54
  10. data/app/assets/javascripts/blocks/looks.js.coffee.erb +2 -1
  11. data/app/assets/javascripts/blocks/motion.js.coffee.erb +4 -16
  12. data/app/assets/javascripts/blocks/operators.js.coffee.erb +2 -1
  13. data/app/assets/javascripts/blocks/pen.js.coffee.erb +2 -1
  14. data/app/assets/javascripts/blocks/ruby.js.coffee.erb +2 -1
  15. data/app/assets/javascripts/blocks/sensing.js.coffee.erb +25 -3
  16. data/app/assets/javascripts/blocks/sound.js.coffee.erb +2 -1
  17. data/app/assets/javascripts/generators/ruby.js.coffee.erb +27 -5
  18. data/app/assets/javascripts/models/source_code.js.coffee +20 -7
  19. data/app/assets/javascripts/views/main_menu_view.js.coffee +5 -7
  20. data/app/assets/stylesheets/editor.css.scss +5 -1
  21. data/app/assets/stylesheets/toolbox.css.scss.erb +29 -24
  22. data/app/controllers/source_codes_controller.rb +7 -36
  23. data/app/helpers/editor_helper.rb +9 -0
  24. data/app/models/concerns/ruby_to_block/block/hardware_button_down_or_up.rb +25 -0
  25. data/app/models/concerns/ruby_to_block/block/hardware_button_not_use_pullup.rb +18 -0
  26. data/app/models/concerns/ruby_to_block/block/hardware_motor_driver.rb +22 -0
  27. data/app/models/concerns/ruby_to_block/block/hardware_motor_driver_set_speed.rb +20 -0
  28. data/app/models/concerns/ruby_to_block/block/hardware_motor_driver_speed.rb +24 -0
  29. data/app/models/concerns/ruby_to_block/block/hardware_on_button_down_or_up.rb +19 -0
  30. data/app/models/concerns/ruby_to_block/block/hardware_operation.rb +15 -0
  31. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_set_speed.rb +22 -0
  32. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_speed.rb +26 -0
  33. data/app/models/concerns/ruby_to_block/block/ruby_p.rb +19 -0
  34. data/app/models/concerns/ruby_to_block/block/{motion_reach_wall.rb → sensing_reach_wall.rb} +1 -1
  35. data/app/models/concerns/ruby_to_block/block/text.rb +3 -2
  36. data/app/models/source_code.rb +20 -0
  37. data/app/views/editor/_toolbox.html.haml +84 -63
  38. data/app/views/editor/index.html.haml +1 -1
  39. data/demos/adjust_2wd_car.rb.xml +179 -0
  40. data/demos/car_chase.rb.xml +129 -126
  41. data/demos/hardware_led.rb.xml +7 -4
  42. data/demos/pong.rb.xml +17 -14
  43. data/demos/star.rb.xml +115 -112
  44. data/lib/smalruby_editor.rb +16 -0
  45. data/lib/smalruby_editor/version.rb +3 -3
  46. data/public/assets/{application-c8991557a0789ac1bc9220f409e7f1c1.js → application-734570836cdba680c1568220a51af40f.js} +216 -86
  47. data/public/assets/{application-c8991557a0789ac1bc9220f409e7f1c1.js.gz → application-734570836cdba680c1568220a51af40f.js.gz} +0 -0
  48. data/public/assets/{application-d4fe6c0f970efe8eab9267fd08718d96.css → application-898cb749439fba4ce44cffeac1216201.css} +37 -9
  49. data/public/assets/{application-d4fe6c0f970efe8eab9267fd08718d96.css.gz → application-898cb749439fba4ce44cffeac1216201.css.gz} +0 -0
  50. data/public/assets/manifest-332a5a1668194028b55103e0ea45c054.json +1 -1
  51. data/smalruby-editor.gemspec +2 -1
  52. data/spec/acceptance/block_mode/blocks/events/on_hit.feature +2 -0
  53. data/spec/acceptance/block_mode/blocks/hardware/button_down_or_up.feature +79 -0
  54. data/spec/acceptance/block_mode/blocks/hardware/button_not_use_pullup.feature +61 -0
  55. data/spec/acceptance/block_mode/blocks/hardware/motor_driver.feature +73 -0
  56. data/spec/acceptance/block_mode/blocks/hardware/motor_driver_speed.feature +93 -0
  57. data/spec/acceptance/block_mode/blocks/hardware/on_button_down_or_up.feature +87 -0
  58. data/spec/acceptance/block_mode/blocks/hardware/two_wheel_drive_car_speed.feature +111 -0
  59. data/spec/acceptance/block_mode/blocks/motion/reach_wall.feature +1 -1
  60. data/spec/acceptance/block_mode/blocks/operators/text.feature +38 -0
  61. data/spec/acceptance/block_mode/blocks/sensing/hit.feature +98 -52
  62. data/spec/acceptance/block_mode/blocks/sensing/reach_wall.feature +98 -0
  63. data/spec/acceptance/block_mode/demo.feature +3 -1
  64. data/spec/acceptance/standalone/save.feature +51 -0
  65. data/spec/helpers/editor_helper_spec.rb +20 -0
  66. data/spec/javascripts/models/source_code_spec.coffee +40 -0
  67. data/spec/models/concerns/ruby_to_block/block/hardware_spec.rb +269 -0
  68. data/spec/models/concerns/ruby_to_block/block/motion_spec.rb +1 -1
  69. data/spec/models/concerns/ruby_to_block/block/{motion_reach_wall_spec.rb → sensing_reach_wall_spec.rb} +2 -2
  70. data/spec/models/concerns/ruby_to_block/block/text_spec.rb +39 -0
  71. data/spec/models/concerns/ruby_to_block_spec.rb +2 -2
  72. data/spec/models/source_code_spec.rb +53 -0
  73. data/spec/steps/base_steps.rb +5 -0
  74. metadata +56 -12
  75. data/demos/rgb_led_anode.rb.xml +0 -83
@@ -2,7 +2,8 @@
2
2
 
3
3
  <%
4
4
  category = 'operators'
5
- color = 100
5
+ require 'smalruby_editor'
6
+ color = SmalrubyEditor::COLORS[category.to_sym]
6
7
  %>
7
8
 
8
9
  # 変数:( ) + ( )
@@ -2,7 +2,8 @@
2
2
 
3
3
  <%
4
4
  category = 'pen'
5
- color = 160
5
+ require 'smalruby_editor'
6
+ color = SmalrubyEditor::COLORS[category.to_sym]
6
7
  %>
7
8
 
8
9
  # ペンを下ろす
@@ -2,7 +2,8 @@
2
2
 
3
3
  <%
4
4
  category = 'ruby'
5
- color = 340
5
+ require 'smalruby_editor'
6
+ color = SmalrubyEditor::COLORS[category.to_sym]
6
7
  %>
7
8
 
8
9
  # 文
@@ -2,7 +2,8 @@
2
2
 
3
3
  <%
4
4
  category = 'sensing'
5
- color = 190
5
+ require 'smalruby_editor'
6
+ color = SmalrubyEditor::COLORS[category.to_sym]
6
7
  %>
7
8
 
8
9
  # 調べるの環境設定
@@ -26,6 +27,27 @@ window.SmalrubyEditor.Sensing =
26
27
  ['中ボタン', 'M_MBUTTON'],
27
28
  ['右ボタン', 'M_RBUTTON'],
28
29
  ]
30
+ DownOrUpDropdown: [
31
+ ['押された', 'down'],
32
+ ['離された', 'up'],
33
+ ]
34
+
35
+ # 条件:端に触れた
36
+ <% n = "#{category}_reach_wall" %>
37
+ Blockly.Blocks['<%= n %>'] =
38
+ init: ()->
39
+ @setHelpUrl('')
40
+ @setColour(<%= color %>)
41
+ @appendDummyInput().appendField('端に触れた')
42
+ @setOutput(true, 'Boolean')
43
+ @setTooltip('')
44
+
45
+ Blockly.Ruby['<%= n %>'] = (block) ->
46
+ Blockly.Ruby.characterMethodCallInput_('reach_wall?')
47
+
48
+ # HACK: 後方互換性のため、motion_reach_wallとして複製する
49
+ Blockly.Blocks['motion_reach_wall'] = Blockly.Blocks['<%= n %>']
50
+ Blockly.Ruby['motion_reach_wall'] = Blockly.Ruby['<%= n %>']
29
51
 
30
52
  # 条件:キーボードの[▼キー]が[▼押された]
31
53
  <% n = "#{category}_input_key_push_or_down" %>
@@ -104,7 +126,7 @@ Blockly.Blocks['<%= n %>'] =
104
126
  @setTooltip('')
105
127
 
106
128
  Blockly.Ruby['<%= n %>'] = (block) ->
107
- char = @getFieldValue('CHAR')
129
+ char = @getCharacterFieldValue()
108
130
  Blockly.Ruby.characterMethodCallInput_('hit?', char)
109
131
 
110
132
  # [ ]と聞いて待つ
@@ -192,7 +214,7 @@ Blockly.Blocks['<%= n %>'] =
192
214
  @setTooltip('')
193
215
 
194
216
  Blockly.Ruby['<%= n %>'] = (block) ->
195
- char = @getFieldValue('CHAR')
217
+ char = @getCharacterFieldValue()
196
218
  property = @getFieldValue('PROPERTY')
197
219
  c = Smalruby.Collections.CharacterSet.findWhere({ name: char })
198
220
  Blockly.Ruby.characterMethodCallInput_(property, null, { object: c })
@@ -2,7 +2,8 @@
2
2
 
3
3
  <%
4
4
  category = 'sound'
5
- color = 300
5
+ require 'smalruby_editor'
6
+ color = SmalrubyEditor::COLORS[category.to_sym]
6
7
  %>
7
8
 
8
9
  # [▼プリセット音声]
@@ -51,6 +51,20 @@ Blockly.Ruby.init = ->
51
51
  @definitions_['receiver_stack'] = ['main']
52
52
  @definitions_['character_stack'] = []
53
53
 
54
+ Blockly.Ruby.defineCharacter = (c) ->
55
+ name = c.get('name')
56
+ blockName = "character_#{name}"
57
+ if !Blockly.Ruby.definitions_[blockName]
58
+ switch c.get('rotationStyle')
59
+ when 'left_right'
60
+ rotationStyle = ', rotation_style: :left_right'
61
+ when 'none'
62
+ rotationStyle = ', rotation_style: :none'
63
+ else
64
+ rotationStyle = ''
65
+ Blockly.Ruby.definitions_[blockName] =
66
+ "#{name} = Character.new(costume: #{Blockly.Ruby.quote_(c.costume())}, x: #{c.get('x')}, y: #{c.get('y')}, angle: #{c.get('angle')}#{rotationStyle})"
67
+
54
68
  Blockly.Ruby.characterStack = ->
55
69
  @definitions_['character_stack']
56
70
 
@@ -159,12 +173,20 @@ Blockly.Ruby.finish = (code) ->
159
173
  Blockly.Ruby.scrubNakedValue = (line) ->
160
174
  line + '\n'
161
175
 
176
+ Blockly.Ruby.escapeChars_ =
177
+ '"': '\\"'
178
+
162
179
  Blockly.Ruby.quote_ = (string) ->
163
- # TODO: 実装すること
164
- # stringに"を含んでいたら、aから順番にstringに含まれるか試して、含ま
165
- # れていない文字を使って%Qa...aとしようかな。でも生成したソースコード
166
- # の可読性が下がりますね。
167
- '\"' + string + '\"'
180
+ # copy and modified goog.string.quote:
181
+ # http://docs.closure-library.googlecode.com/git/namespace_goog_string.html
182
+ s = String(string)
183
+ sb = ['"']
184
+ for i in [0...s.length]
185
+ do (i) ->
186
+ ch = s.charAt(i)
187
+ sb[i + 1] = Blockly.Ruby.escapeChars_[ch] || ch
188
+ sb.push('"')
189
+ sb.join('')
168
190
 
169
191
  Blockly.Ruby.scrub_ = (block, code) ->
170
192
  if code == null
@@ -15,15 +15,28 @@ Smalruby.SourceCode = Backbone.Model.extend
15
15
  filename = '1.rb'
16
16
  @set('filename', filename)
17
17
 
18
- if @get('filename').match(/\.xml$/)
19
- data = Smalruby.dumpXml()
20
- else
21
- if window.blockMode
22
- data = Blockly.Ruby.workspaceToCode()
18
+ unless @get('data')
19
+ if @get('filename').match(/\.xml$/)
20
+ data = Smalruby.dumpXml()
23
21
  else
24
- data = window.textEditor.getSession().getDocument().getValue()
22
+ if window.blockMode
23
+ data = Blockly.Ruby.workspaceToCode()
24
+ else
25
+ data = window.textEditor.getSession().getDocument().getValue()
26
+
27
+ @set('data', data)
25
28
 
26
- @set('data', data)
29
+ getRbxmlFilename: ->
30
+ filename = @get('filename')
31
+ if filename.match(/\.rb\.xml$/)
32
+ filename
33
+ else
34
+ if filename.match(/\.rb$/)
35
+ filename + '.xml'
36
+ else if filename.match(/\.xml$/)
37
+ filename.replace(/\.xml$/, '.rb.xml')
38
+ else
39
+ filename + '.rb.xml'
27
40
 
28
41
  run: ->
29
42
  @post_('run')
@@ -86,9 +86,8 @@ Smalruby.MainMenuView = Backbone.View.extend
86
86
 
87
87
  sourceCode = @getSourceCode()
88
88
 
89
- filename = sourceCode.get('filename')
90
- filename += '.xml' unless filename.match(/\.xml$/)
91
- xmlSourceCode = new Smalruby.SourceCode({ filename: filename })
89
+ xmlSourceCode =
90
+ new Smalruby.SourceCode({ filename: sourceCode.getRbxmlFilename() })
92
91
 
93
92
  clearMessages()
94
93
 
@@ -200,11 +199,10 @@ Smalruby.MainMenuView = Backbone.View.extend
200
199
  $('#filename').focus()
201
200
  return
202
201
 
202
+ sourceCode = @getSourceCode()
203
203
  if window.blockMode
204
- filename += '.xml' unless filename.match(/\.xml$/)
205
- sourceCode = new Smalruby.SourceCode({ filename: filename })
206
- else
207
- sourceCode = @getSourceCode()
204
+ sourceCode =
205
+ new Smalruby.SourceCode({ filename: sourceCode.getRbxmlFilename() })
208
206
 
209
207
  clearMessages()
210
208
 
@@ -13,7 +13,11 @@ $left-pane-width: $character-size + $margin * 2;
13
13
  #messages {
14
14
  position: absolute;
15
15
  right: 20px;
16
- z-index: 9999;
16
+ z-index: 999;
17
+ max-height: 80%;
18
+ overflow: auto;
19
+ bottom: 20px;
20
+ width: 25%;
17
21
  }
18
22
 
19
23
  .left-pane {
@@ -23,30 +23,35 @@
23
23
  }.join
24
24
  end
25
25
 
26
- hues = %w(
27
- 208
28
- 208
29
- 208
30
- 208
31
- 270
32
- 300
33
- 160
34
- 330
35
- 330
36
- 33
37
- 43
38
- 43
39
- 43
40
- 43
41
- 190
42
- 100
43
- 100
44
- 100
45
- 100
46
- 340
47
- 340
48
- 340
49
- ).map(&:to_i)
26
+ require 'smalruby_editor'
27
+ colors = SmalrubyEditor::COLORS
28
+
29
+ hues = [
30
+ colors[:motion],
31
+ colors[:motion],
32
+ colors[:motion],
33
+ colors[:motion],
34
+ colors[:looks],
35
+ colors[:sound],
36
+ colors[:pen],
37
+ colors[:data],
38
+ colors[:data],
39
+ colors[:events],
40
+ colors[:control],
41
+ colors[:control],
42
+ colors[:control],
43
+ colors[:control],
44
+ colors[:sensing],
45
+ colors[:sensing],
46
+ colors[:sensing],
47
+ colors[:operators],
48
+ colors[:operators],
49
+ colors[:operators],
50
+ colors[:operators],
51
+ colors[:etc],
52
+ colors[:etc],
53
+ colors[:etc],
54
+ ]
50
55
 
51
56
  colors = hues.map { |h|
52
57
  [hsv_to_rgb(h, 100, 80), hsv_to_rgb(h, 100, 100)]
@@ -4,50 +4,21 @@ require 'nkf'
4
4
  class SourceCodesController < ApplicationController
5
5
  before_filter :check_whether_standalone, only: [:write, :run, :load_local]
6
6
 
7
- # デモプログラム
8
- DEMO_PROGRAMS =
9
- [
10
- {
11
- title: '車のおいかけっこ',
12
- filename: 'car_chase.rb',
13
- imageUrl: '/smalruby/assets/car2.png',
14
- },
15
- {
16
- title: 'クリックスターだにゃ~',
17
- filename: 'star.rb',
18
- imageUrl: '/smalruby/assets/cat1.png',
19
- },
20
- {
21
- title: 'ピンポンゲーム',
22
- filename: 'pong.rb',
23
- imageUrl: '/smalruby/assets/cat2.png',
24
- },
25
- {
26
- title: 'ライトをぴかっとさせるでよ',
27
- filename: 'hardware_led.rb',
28
- imageUrl: '/smalruby/assets/frog1.png',
29
- },
30
- ]
31
-
32
7
  def index
33
8
  res = {
34
9
  localPrograms: [],
35
10
  demoPrograms: [],
36
11
  }
37
12
  if standalone?
38
- local_program_paths.each do |path|
39
- # TODO: XMLからタイトルを抽出する
40
- # TODO: XMLからキャラクターの画像を抽出する
41
- filename = rb_basename(path)
42
- res[:localPrograms] << {
43
- title: filename,
44
- filename: filename,
45
- }
46
- end
13
+ res[:localPrograms] = local_program_paths.map { |path|
14
+ SourceCode.new(filename: path.basename.to_s, data: path.read).summary
15
+ }
47
16
  end
48
17
 
49
- # TODO: XMLから情報を抽出する
50
- res[:demoPrograms] = DEMO_PROGRAMS
18
+ res[:demoPrograms] = Pathname.glob(Rails.root.join('demos/*.rb.xml')).map {
19
+ |path|
20
+ SourceCode.new(filename: path.basename.to_s, data: path.read).summary
21
+ }
51
22
 
52
23
  render json: res
53
24
  end
@@ -17,6 +17,15 @@ module EditorHelper
17
17
  %(<field name="#{h name}">#{h value}</field>).html_safe
18
18
  end
19
19
 
20
+ # ツールボックスのブロックに対して、PINの入力フィールドの値を設定する
21
+ #
22
+ # @param [String] value ピン
23
+ # @param [String] name 名前
24
+ # @return [String] XML
25
+ def toolbox_pin_field(value, name = 'PIN')
26
+ %(<field name="#{h name}">#{h value}</field>).html_safe
27
+ end
28
+
20
29
  # ツールボックスのブロックに対して、数値型の入力のブロックを設定する
21
30
  #
22
31
  # @param [String] name 入力値の名前
@@ -0,0 +1,25 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareButtonDownOrUp < Value
4
+ include CharacterOperation
5
+ include HardwareOperation
6
+
7
+ blocknize '^\s*' + CHAR_RE +
8
+ 'button\(' + DIO_PIN_RE + '\)\.(down|up)\?\s*$',
9
+ value: true
10
+
11
+ def self.process_match_data(md, context)
12
+ md2 = regexp.match(md[type])
13
+
14
+ character = get_character(context, md2[1])
15
+ return false if context.receiver && context.receiver != character
16
+
17
+ block = new(fields: { PIN: md2[2], DOU: md2[3] })
18
+ context.add_value(block)
19
+ block.character = character
20
+
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareButtonNotUsePullup < CharacterMethodCall
4
+ include HardwareOperation
5
+
6
+ blocknize '^\s*' + CHAR_RE +
7
+ 'button\(' + DIO_PIN_RE + '\)\.not_use_pullup\s*$',
8
+ statement: true
9
+
10
+ def self.process_match_data(md, context)
11
+ md2 = regexp.match(md[type])
12
+ add_character_method_call_block(context, md2[1],
13
+ new(fields: { PIN: md2[2] }))
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareMotorDriver < CharacterMethodCall
5
+ # rubocop:disable LineLength
6
+ blocknize '^\s*' + CHAR_RE +
7
+ 'motor_driver\("(D(?:3|5|6|9|10|11))"\)\.(forward|backward|stop)\s*$',
8
+ statement: true
9
+ # rubocop:enable LineLength
10
+
11
+ attr_accessor :method_name
12
+
13
+ def self.process_match_data(md, context)
14
+ md2 = regexp.match(md[type])
15
+ add_character_method_call_block(context, md2[1],
16
+ new(fields: { PIN: md2[2],
17
+ METHOD: md2[3] }))
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareMotorDriverSetSpeed < CharacterMethodCall
5
+ include HardwareOperation
6
+
7
+ blocknize '^\s*' + CHAR_RE +
8
+ 'motor_driver\(' + PWM_PIN_RE + '\)\.speed\s*=\s*(\S+)\s*$',
9
+ statement: true, inline: true
10
+
11
+ def self.process_match_data(md, context)
12
+ md2 = regexp.match(md[type])
13
+ add_character_method_call_block(context, md2[1],
14
+ new(fields: { PIN: md2[2] }),
15
+ SPEED: md2[3])
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end