smalruby-editor 0.1.15 → 0.1.16

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +16 -1
  3. data/app/assets/javascripts/blocks/character.js.coffee.erb +8 -1
  4. data/app/assets/javascripts/blocks/hardware.js.coffee.erb +59 -7
  5. data/app/assets/javascripts/blocks/motion.js.coffee.erb +1 -2
  6. data/app/assets/javascripts/models/character.js.coffee +27 -0
  7. data/app/assets/javascripts/smalruby.js.coffee +4 -0
  8. data/app/assets/javascripts/views/character_modal_view.js.coffee +22 -1
  9. data/app/assets/javascripts/views/character_selector_view.js.coffee +7 -6
  10. data/app/assets/stylesheets/application.css +8 -0
  11. data/app/assets/stylesheets/editor.css.scss +15 -5
  12. data/app/controllers/application_controller.rb +4 -7
  13. data/app/models/concerns/ruby_to_block/block/character.rb +14 -6
  14. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car.rb +1 -1
  15. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_commands.rb +15 -0
  16. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_run.rb +19 -0
  17. data/app/models/concerns/ruby_to_block/block/motion_set_x.rb +1 -24
  18. data/app/models/concerns/ruby_to_block/block/motion_set_x_y.rb +21 -0
  19. data/app/models/source_code.rb +9 -6
  20. data/app/views/editor/_block_tab.html.haml +3 -1
  21. data/app/views/editor/_character_modal.html.haml +14 -5
  22. data/app/views/editor/_toolbox.html.haml +91 -78
  23. data/bin/smalruby-editor +15 -0
  24. data/lib/smalruby_editor/version.rb +1 -1
  25. data/lib/smalruby_editor.rb +39 -4
  26. data/public/assets/{application-51ab300acd1779bfba20b099e7000b7e.css → application-7f560d8d6d224f87269691c57ca9a376.css} +23 -9
  27. data/public/assets/{application-51ab300acd1779bfba20b099e7000b7e.css.gz → application-7f560d8d6d224f87269691c57ca9a376.css.gz} +0 -0
  28. data/public/assets/{application-dc485e2270d6c5fce20c149d1e2c4f8d.js → application-842ac8f5aa3fcc87bbb0e8b3a0fef5d7.js} +148 -21
  29. data/public/assets/{application-dc485e2270d6c5fce20c149d1e2c4f8d.js.gz → application-842ac8f5aa3fcc87bbb0e8b3a0fef5d7.js.gz} +0 -0
  30. data/public/assets/manifest-332a5a1668194028b55103e0ea45c054.json +1 -1
  31. data/smalruby-editor.gemspec +1 -1
  32. data/spec/acceptance/block_mode/blocks/motion/set_x_y.feature +2 -4
  33. data/spec/lib/smalruby_editor_spec.rb +12 -0
  34. data/spec/models/concerns/ruby_to_block/block/hardware_spec.rb +90 -10
  35. data/spec/models/concerns/ruby_to_block/block/motion_spec.rb +3 -6
  36. metadata +11 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cb16d8aecfe041f7828d1eb715235f0ce8cc79e9
4
- data.tar.gz: 6b6a21336c99739958984d7c0220fbaa3a211754
3
+ metadata.gz: 110fbf90c4792bd8f54a5186633e8ffd33b3ed82
4
+ data.tar.gz: e3cfd0fa9043b7d3420fd9cc7eb129f4374b343e
5
5
  SHA512:
6
- metadata.gz: f6f20cea2500aad412b097b4f5bef82481f34fdf49aee63ff7c1b9279350408d7ecb9af83a3362f3e4c15bdfdeecfb3f9dd7b251a76a797e2c999345aa4b3807
7
- data.tar.gz: c6aef9c719d5498d2bd10b64248b6485793fb73fe2114b4a040da07d295511234c88dacb753644e7304b740f6d930ca5f5b826d99b673423d6572a025bc2b21f
6
+ metadata.gz: 606b278152c481b67cead9cdb88c1858f72478ba7b3ed765996eca1c33785cb33900164a85a4061690369323ce58cf8dba7834a7a126a722f0d99948fc715572
7
+ data.tar.gz: c8ffe0e9d3a24b2242478cbbf57b518b34f905e3046e449e9813adef841b3c40571825aa0be38328c4a32c35389b0785b3eae14ef0c778b79e28d128612250ad
data/README.rdoc CHANGED
@@ -11,10 +11,24 @@ The smalruby-editor is a visual programming editor that can create a Ruby script
11
11
  * DEMO: http://smalruby.herokuapp.com/demo/
12
12
  * DEMO(Arduino): http://smalruby.herokuapp.com/demo/rgb_led_anode/
13
13
 
14
- The smalruby-editor is a part of the Smalruby Project.
14
+ The smalruby-editor is a part of the Smalruby (http://smalruby.jp) Project.
15
15
 
16
16
  The Smalruby(smɔ́ːrúːbi) Project will provide a Ruby learning environment for middle school students from the upper grades of elementary school. The goal of this project is to achieve software and community sites such as the {Scratch}[http://scratch.mit.edu/] in Ruby. The Scratch has experience as educational programming environment can be used in elementary school. This project consists of the following elements.
17
17
 
18
+ == Installation (for User)
19
+
20
+ requirements:
21
+
22
+ * Windows or UNIX like OS (Mac OS X, Linux, etc...)
23
+ * Ruby 2.0.0-p353 or higher.
24
+ * dxruby_sdl (only Mac OS X and Linux): https://github.com/takaokouji/dxruby_sdl/
25
+ * rsdl (only Mac OS X): http://www.kumaryu.net/proj/ruby-rsdl/
26
+
27
+ execute below commands.
28
+
29
+ gem install smalruby-editor
30
+ smalruby-editor
31
+
18
32
  == Installation (for Developer)
19
33
 
20
34
  requirements:
@@ -32,6 +46,7 @@ execute below commands.
32
46
  rake db:create
33
47
  rake db:migrate
34
48
  rake
49
+ touch tmp/standalone
35
50
  rails server
36
51
 
37
52
  access <tt>localhost:3000</tt> with your web browser.
@@ -65,8 +65,15 @@ Blockly.Blocks['<%= n %>'] =
65
65
 
66
66
  Blockly.Ruby['<%= n %>'] = (block) ->
67
67
  c = block.character
68
+ switch c.get('rotationStyle')
69
+ when 'left_right'
70
+ rotationStyle = ', rotation_style: :left_right'
71
+ when 'none'
72
+ rotationStyle = ', rotation_style: :none'
73
+ else
74
+ rotationStyle = ''
68
75
  Blockly.Ruby.definitions_["character_#{c.get('name')}"] =
69
- "#{c.get('name')} = Character.new(costume: #{Blockly.Ruby.quote_(c.costume())}, x: #{c.get('x')}, y: #{c.get('y')}, angle: #{c.get('angle')})"
76
+ "#{c.get('name')} = Character.new(costume: #{Blockly.Ruby.quote_(c.costume())}, x: #{c.get('x')}, y: #{c.get('y')}, angle: #{c.get('angle')}#{rotationStyle})"
70
77
  Blockly.Ruby.cs_().push(c)
71
78
  try
72
79
  targetBlock = block.getInputTargetBlock('DO')
@@ -29,6 +29,8 @@ acDropdown = [
29
29
  ['カソード', 'cathode']
30
30
  ]
31
31
 
32
+ twoWDPinDropdown = (["D#{n}", "D#{n}"] for n in [2..10])
33
+
32
34
  # ハードウェアを準備する
33
35
  <% n = "#{category}_init_hardware" %>
34
36
  Blockly.Blocks['<%= n %>'] =
@@ -241,12 +243,13 @@ Blockly.Ruby['<%= n %>'] = (block) ->
241
243
  Blockly.Ruby.characterMethodCall_("servo(#{Blockly.Ruby.quote_(pin)}).position = #{pos}")
242
244
 
243
245
  # 「車」サブジャンル
246
+ <% subcategory = 'two_wheel_drive_car' %>
244
247
 
245
- # 2WD車[▼ピン]を進める」ブロック
246
- # 2WD車[▼ピン]をバックさせる」ブロック
247
- # 2WD車[▼ピン]を左に曲げる」ブロック
248
- # 2WD車[▼ピン]を右に曲げる」ブロック
249
- # 2WD車[▼ピン]を止める」ブロック
248
+ # 2WD車[▼ピン]を進める
249
+ # 2WD車[▼ピン]をバックさせる
250
+ # 2WD車[▼ピン]を左に曲げる
251
+ # 2WD車[▼ピン]を右に曲げる
252
+ # 2WD車[▼ピン]を止める
250
253
  <%
251
254
  [
252
255
  ['forward', '進める'],
@@ -255,7 +258,7 @@ Blockly.Ruby['<%= n %>'] = (block) ->
255
258
  ['turn_right', '右に曲げる'],
256
259
  ['stop', '止める'],
257
260
  ].each do |method, label|
258
- n = "#{category}_two_wheel_drive_car_#{method}"
261
+ n = "#{category}_#{subcategory}_#{method}"
259
262
  %>
260
263
 
261
264
  Blockly.Blocks['<%= n %>'] =
@@ -266,7 +269,7 @@ Blockly.Blocks['<%= n %>'] =
266
269
  @setColour(<%= color %>)
267
270
  @appendDummyInput()
268
271
  .appendField('2WD車')
269
- .appendField(new Blockly.FieldDropdown(dropdown), 'PIN')
272
+ .appendField(new Blockly.FieldDropdown(twoWDPinDropdown), 'PIN')
270
273
  .appendField('を<%= label %>')
271
274
  @setInputsInline(true)
272
275
  @setPreviousStatement(true)
@@ -279,6 +282,55 @@ Blockly.Ruby['<%= n %>'] = (block) ->
279
282
  Blockly.Ruby.characterMethodCall_("two_wheel_drive_car(#{Blockly.Ruby.quote_(pin)}).<%= method %>")
280
283
  <% end %>
281
284
 
285
+ # 2WD車[▼ピン]を( )秒[▼コマンド]
286
+ <% n = "#{category}_#{subcategory}_run" %>
287
+ Blockly.Blocks['<%= n %>'] =
288
+ init: ()->
289
+ @setHelpUrl('')
290
+ @setColour(<%= color %>)
291
+ @appendDummyInput()
292
+ .appendField('2WD車')
293
+ .appendField(new Blockly.FieldDropdown(twoWDPinDropdown), 'PIN')
294
+ .appendField('を')
295
+ @appendValueInput('SEC')
296
+ .setCheck('Number')
297
+ @appendDummyInput()
298
+ .appendField('秒')
299
+ @appendValueInput('COMMAND').setCheck('String')
300
+ @setInputsInline(true)
301
+ @setPreviousStatement(true)
302
+ @setNextStatement(true)
303
+ @setTooltip('')
304
+
305
+ Blockly.Ruby['<%= n %>'] = (block) ->
306
+ pin = @getFieldValue('PIN')
307
+ sec = Blockly.Ruby.valueToCode(@, 'SEC', Blockly.Ruby.ORDER_NONE) || 0
308
+ command = Blockly.Ruby.valueToCode(@, 'COMMAND', Blockly.Ruby.ORDER_NONE) || Blockly.Ruby.quote_('stop')
309
+
310
+ Blockly.Ruby.characterMethodCall_("two_wheel_drive_car(#{Blockly.Ruby.quote_(pin)}).run(command: #{command}, sec: #{sec})")
311
+
312
+ # [▼コマンド]
313
+ <% n = "#{category}_#{subcategory}_commands" %>
314
+ Blockly.Blocks['<%= n %>'] =
315
+ init: ()->
316
+ commands = [
317
+ ['進める', 'forward'],
318
+ ['バックさせる', 'backward'],
319
+ ['左に曲げる', 'turn_left'],
320
+ ['右に曲げる', 'turn_right'],
321
+ ['止める', 'stop'],
322
+ ]
323
+ @setHelpUrl('')
324
+ @setColour(<%= color %>)
325
+ @appendDummyInput()
326
+ .appendField(new Blockly.FieldDropdown(commands), 'COMMAND')
327
+ @setOutput(true, 'String')
328
+ @setTooltip('')
329
+
330
+ Blockly.Ruby['<%= n %>'] = (block) ->
331
+ code = Blockly.Ruby.quote_(@getFieldValue('COMMAND'))
332
+ [code, Blockly.Ruby.ORDER_ATOMIC]
333
+
282
334
  # 「ボタン」サブジャンル
283
335
 
284
336
  # 条件:ボタン[▼]を押している
@@ -119,8 +119,7 @@ Blockly.Blocks['<%= n %>'] =
119
119
  Blockly.Ruby['<%= n %>'] = (block) ->
120
120
  x = Blockly.Ruby.valueToCode(@, 'X', Blockly.Ruby.ORDER_NONE) || '0'
121
121
  y = Blockly.Ruby.valueToCode(@, 'Y', Blockly.Ruby.ORDER_NONE) || '0'
122
- Blockly.Ruby.characterSetVariable_('x', x) +
123
- Blockly.Ruby.characterSetVariable_('y', y)
122
+ Blockly.Ruby.characterSetVariable_('position', "[#{x}, #{y}]")
124
123
 
125
124
  # マウスポインターへ行く
126
125
  <% n = "#{category}_go_to_mouse" %>
@@ -6,6 +6,7 @@ Smalruby.Character = Backbone.Model.extend({
6
6
  x: 0
7
7
  y: 0
8
8
  angle: 0
9
+ rotationStyle: 'free'
9
10
  visible: true
10
11
  using: false
11
12
 
@@ -64,6 +65,32 @@ Smalruby.Character = Backbone.Model.extend({
64
65
  i = 0 if i >= @get('costumes').length
65
66
  @set({ 'costumeIndex': i })
66
67
  i
68
+
69
+ rotationStyleIconName: ->
70
+ switch @get('rotationStyle')
71
+ when 'free'
72
+ 'icon-repeat'
73
+ when 'left_right'
74
+ 'icon-resize-horizontal'
75
+ when 'none'
76
+ 'icon-arrow-right'
77
+
78
+ rotateImage: (selector) ->
79
+ angle = @get('angle')
80
+ switch @get('rotationStyle')
81
+ when 'free'
82
+ transformValue = "rotate(#{angle}deg) scaleX(1)"
83
+ when 'left_right'
84
+ if angle < 90 || angle >= 270
85
+ transformValue = "rotate(0deg) scaleX(1)"
86
+ else
87
+ transformValue = "rotate(0deg) scaleX(-1)"
88
+ when 'none'
89
+ transformValue = "rotate(0deg) scaleX(1)"
90
+ $(selector).css
91
+ '-moz-transform': transformValue
92
+ '-webkit-transform': transformValue
93
+ transform: transformValue
67
94
  }, {
68
95
  PRESET_COSTUMES: [
69
96
  'car1.png'
@@ -131,6 +131,7 @@ window.Smalruby =
131
131
  x: parseInt(xmlChild.getAttribute('x'), 10)
132
132
  y: parseInt(xmlChild.getAttribute('y'), 10)
133
133
  angle: parseInt(xmlChild.getAttribute('angle'), 10)
134
+ rotationStyle: xmlChild.getAttribute('rotation_style') || 'free'
134
135
  chars.push(c)
135
136
  i++
136
137
  Smalruby.Collections.CharacterSet.reset(chars)
@@ -146,6 +147,9 @@ window.Smalruby =
146
147
  e.setAttribute('name', c.get('name'))
147
148
  e.setAttribute('costumes', c.get('costumes').join(','))
148
149
  e.setAttribute('angle', c.get('angle'))
150
+ rotationStyle = c.get('rotationStyle')
151
+ if rotationStyle != 'free'
152
+ e.setAttribute('rotation_style', rotationStyle)
149
153
  xmlDom.insertBefore(e, blocklyDom)
150
154
  Blockly.Xml.domToPrettyText(xmlDom)
151
155
 
@@ -4,6 +4,9 @@ Smalruby.CharacterModalView = Backbone.View.extend
4
4
 
5
5
  events:
6
6
  'click #character-modal-costume-selector a': 'onSelectCostume'
7
+ 'click #character_rotation_style_free': 'onRotationStyleFree'
8
+ 'click #character_rotation_style_left_right': 'onRotationStyleLeftRight'
9
+ 'click #character_rotation_style_none': 'onRotationStyleNone'
7
10
  'click #character-modal-ok-button': 'onOk'
8
11
 
9
12
  previewZoomLevel: 0.5
@@ -57,6 +60,7 @@ Smalruby.CharacterModalView = Backbone.View.extend
57
60
  @listenTo(@model, 'change:y', @onChangeY)
58
61
  @listenTo(@model, 'change:angle', @onChangeAngle)
59
62
  @listenTo(@model, 'change:costumes', @onChangeCostumes)
63
+ @listenTo(@model, 'change:rotationStyle', @onChangeRotationStyle)
60
64
  @listenTo(@model, 'change', @onChange)
61
65
 
62
66
  @callAllOnChangeAttributes_()
@@ -85,6 +89,7 @@ Smalruby.CharacterModalView = Backbone.View.extend
85
89
  @onChangeY(@model, @model.get('y'))
86
90
  @onChangeAngle(@model, @model.get('angle'))
87
91
  @onChangeCostumes(@model, @model.get('costumes'))
92
+ @onChangeRotationStyle(@model, @model.get('rotationStyle'))
88
93
 
89
94
  onChangeName: (model, value, options) ->
90
95
  @$el.find('input[name="character[name]"]').val(value)
@@ -103,11 +108,13 @@ Smalruby.CharacterModalView = Backbone.View.extend
103
108
  @$el.find('input[name="character[angle]"]').val(value)
104
109
  $('#character_angle_value').text("#{value}°")
105
110
  rotate = "rotate(#{value}deg)"
106
- $('#character-modal-character').css
111
+ $('#character_angle_vector').css
107
112
  '-moz-transform': rotate
108
113
  '-webkit-transform': rotate
109
114
  transform: rotate
110
115
 
116
+ @model.rotateImage('#character-modal-character')
117
+
111
118
  onChangeCostumes: (model, value, options) ->
112
119
  img = $('<img>').attr
113
120
  src: model.costumeUrl()
@@ -123,6 +130,11 @@ Smalruby.CharacterModalView = Backbone.View.extend
123
130
  else
124
131
  @readImageSizeflag = true
125
132
 
133
+ onChangeRotationStyle: (model, value, options) ->
134
+ $('#character_rotation_style button.btn').removeClass('btn-primary')
135
+ $("#character_rotation_style_#{value}").addClass('btn-primary')
136
+ @onChangeAngle(@model, @model.get('angle'))
137
+
126
138
  onChange: (model, options) ->
127
139
  return unless @target
128
140
 
@@ -157,6 +169,15 @@ Smalruby.CharacterModalView = Backbone.View.extend
157
169
 
158
170
  @model.set(attrs)
159
171
 
172
+ onRotationStyleFree: ->
173
+ @model.set({ rotationStyle: 'free' })
174
+
175
+ onRotationStyleLeftRight: ->
176
+ @model.set({ rotationStyle: 'left_right' })
177
+
178
+ onRotationStyleNone: ->
179
+ @model.set({ rotationStyle: 'none' })
180
+
160
181
  onOk: ->
161
182
  @$el.modal('hide')
162
183
  if @target
@@ -5,7 +5,7 @@ Smalruby.CharacterSelectorView = Backbone.View.extend({
5
5
  initialize: ->
6
6
  @klass = Smalruby.CharacterSelectorView
7
7
 
8
- @listenTo(@model, name, @render) for name in ['add', 'remove', 'reset', 'change']
8
+ @listenTo(@model, name, @onChange) for name in ['add', 'remove', 'reset', 'change']
9
9
 
10
10
  @templateText = $('#character-selector-template').text()
11
11
 
@@ -49,15 +49,16 @@ Smalruby.CharacterSelectorView = Backbone.View.extend({
49
49
  if character.get('using')
50
50
  removeButton.hide()
51
51
 
52
- rotate = "rotate(#{character.get('angle')}deg)"
53
52
  img = html.find('img')
54
- img.css
55
- '-moz-transform': rotate
56
- '-webkit-transform': rotate
57
- transform: rotate
53
+ character.rotateImage(img)
58
54
  img.on 'dragstart', (e) ->
59
55
  e.preventDefault()
60
56
 
57
+ onChange: ->
58
+ unless Smalruby.blocklyLoading
59
+ Smalruby.changedAfterTranslating = true
60
+ window.changed = true
61
+ @render()
61
62
 
62
63
  addBlock_: (character) ->
63
64
  newBlock = new Blockly.Block(Blockly.mainWorkspace, 'character_new')
@@ -17,3 +17,11 @@ html, body {
17
17
  height: 100%;
18
18
  margin: 0;
19
19
  }
20
+
21
+ body {
22
+ user-select: none;
23
+ -moz-user-select: none;
24
+ -khtml-user-select: none;
25
+ -webkit-user-select: none;
26
+ -ms-user-select: none;
27
+ }
@@ -168,6 +168,11 @@ $left-pane-width: $character-size + $margin * 2;
168
168
  img, div {
169
169
  margin: -$border-size;
170
170
  }
171
+
172
+ img {
173
+ max-width: $character-size;
174
+ max-height: $character-size;
175
+ }
171
176
  }
172
177
 
173
178
  a.character:hover {
@@ -235,11 +240,11 @@ $left-pane-width: $character-size + $margin * 2;
235
240
 
236
241
  $attributes-height: 160px;
237
242
 
238
- $left-pane-width: $preview-width;
243
+ $left-pane-width: $preview-width + 2px;
239
244
  $right-pane-width: $character-size * 3 + $modal-body-margin;
240
245
 
241
246
  $modal-width: $left-pane-width + $right-pane-width + $modal-margin * 2;
242
- $modal-height: $preview-height + $attributes-height + $modal-margin * 2;
247
+ $modal-height: $preview-height + 2px + $attributes-height + $modal-margin * 2;
243
248
 
244
249
  width: $modal-width;
245
250
  height: $modal-height;
@@ -259,7 +264,8 @@ $left-pane-width: $character-size + $margin * 2;
259
264
 
260
265
  width: $preview-width;
261
266
  height: $preview-height;
262
- background-color: black;
267
+ background-color: white;
268
+ border: 1px solid gray;
263
269
  overflow: hidden;
264
270
 
265
271
  #character-modal-character {
@@ -289,15 +295,19 @@ $left-pane-width: $character-size + $margin * 2;
289
295
  margin-bottom: 8px;
290
296
 
291
297
  .control-label {
292
- width: 100px;
298
+ width: 50px;
293
299
  }
294
300
 
295
301
  .controls {
296
- margin-left: 100px + $modal-body-margin;
302
+ margin-left: 50px + $modal-body-margin;
297
303
 
298
304
  input[type=range] {
299
305
  padding: 0;
300
306
  }
307
+
308
+ span#character_angle_vector {
309
+ display: inline-block;
310
+ }
301
311
  }
302
312
  }
303
313
  }
@@ -1,4 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
+
3
+ require 'smalruby_editor'
4
+
2
5
  class ApplicationController < ActionController::Base
3
6
  # Prevent CSRF attacks by raising an exception.
4
7
  # For APIs, you may want to use :null_session instead.
@@ -24,13 +27,7 @@ class ApplicationController < ActionController::Base
24
27
 
25
28
  # Raspberry Piかどうかを返す
26
29
  def raspberrypi?
27
- if Rails.env != 'test' &&
28
- (ENV['SMALRUBY_EDITOR_RASPBERRYPI_MODE'] ||
29
- File.exist?(Rails.root.join('tmp', 'raspberrypi')))
30
- true
31
- else
32
- RbConfig::CONFIG['arch'] == 'armv6l-linux-eabihf'
33
- end
30
+ SmalrubyEditor.raspberrypi?
34
31
  end
35
32
 
36
33
  def check_whether_standalone
@@ -4,7 +4,7 @@ module RubyToBlock
4
4
  # ソースコードに含まれるキャラクターを表現するクラス
5
5
  class Character < Base
6
6
  # rubocop:disable LineLength
7
- blocknize '^\s*(\S+)\s*=\s*Character\.new\(costume:\s*"(\s*[^"]+\s*)"\s*,\s*x:\s*(\s*\d+\s*)\s*,\s*y:\s*(\s*\d+\s*)\s*,\s*angle:\s*(\s*\d+\s*)\)\s*$',
7
+ blocknize '^\s*(\S+)\s*=\s*Character\.new\(costume:\s*"(\s*[^"]+\s*)"\s*,\s*x:\s*(\s*\d+\s*)\s*,\s*y:\s*(\s*\d+\s*)\s*,\s*angle:\s*(\s*\d+\s*)(?:,\s*rotation_style:\s*\s*:(free|left_right|none)\s*)?\)\s*$',
8
8
  statement: true
9
9
  # rubocop:enable LineLength
10
10
 
@@ -13,12 +13,14 @@ module RubyToBlock
13
13
  attr_accessor :x
14
14
  attr_accessor :y
15
15
  attr_accessor :angle
16
+ attr_accessor :rotation_style
16
17
 
17
18
  def self.process_match_data(md, context)
18
19
  md2 = regexp.match(md[type])
19
20
  name = md2[1]
20
21
  context[:characters][name] = new(name: name, costumes: [md2[2]],
21
- x: md2[3], y: md2[4], angle: md2[5])
22
+ x: md2[3], y: md2[4], angle: md2[5],
23
+ rotation_style: md2[6] || 'free')
22
24
 
23
25
  true
24
26
  end
@@ -29,13 +31,19 @@ module RubyToBlock
29
31
  @x = options[:x]
30
32
  @y = options[:y]
31
33
  @angle = options[:angle]
34
+ @rotation_style = options[:rotation_style]
32
35
  end
33
36
 
34
37
  def to_xml(parent)
35
- parent.add_element('character',
36
- 'name' => @name,
37
- 'x' => @x, 'y' => @y, 'angle' => @angle,
38
- 'costumes' => @costumes.join(','))
38
+ attrs = {
39
+ 'name' => @name,
40
+ 'x' => @x,
41
+ 'y' => @y,
42
+ 'angle' => @angle,
43
+ 'costumes' => @costumes.join(',')
44
+ }
45
+ attrs['rotationStyle'] = @rotation_style if @rotation_style != 'free'
46
+ parent.add_element('character', attrs)
39
47
  end
40
48
  end
41
49
  end
@@ -3,7 +3,7 @@ module RubyToBlock
3
3
  module Block
4
4
  class HardwareTwoWheelDriveCar < CharacterMethodCall
5
5
  # rubocop:disable LineLength
6
- blocknize '^\s*' + CHAR_RE + 'two_wheel_drive_car\("(D(?:[2-9]|10))"\).(forward|backward|turn_left|turn_right|stop)\s*$',
6
+ blocknize '^\s*' + CHAR_RE + 'two_wheel_drive_car\("(D(?:[2-9]|10))"\)\.(forward|backward|turn_left|turn_right|stop)\s*$',
7
7
  statement: true
8
8
  # rubocop:enable LineLength
9
9
 
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareTwoWheelDriveCarCommands < Value
5
+ blocknize '^\s*"(forward|backward|turn_left|turn_right|stop)"\s*$',
6
+ value: true, priority: 1
7
+
8
+ def self.process_match_data(md, context)
9
+ md2 = regexp.match(md[type])
10
+ context.add_value(new(fields: { COMMAND: md2[1] }))
11
+ true
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareTwoWheelDriveCarRun < CharacterMethodCall
5
+ # rubocop:disable LineLength
6
+ blocknize '^\s*' + CHAR_RE + 'two_wheel_drive_car\("(D(?:[2-9]|10))"\)\.run\(command:\s*("[^"]*")\s*,\s*sec:\s*(\d+)\)\s*$',
7
+ statement: true, inline: true
8
+ # rubocop:enable LineLength
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
+ SEC: md2[4], COMMAND: md2[3])
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -7,32 +7,9 @@ module RubyToBlock
7
7
 
8
8
  def self.process_match_data(md, context)
9
9
  md2 = regexp.match(md[type])
10
- block = add_character_method_call_block(context, md2[1], new,
11
- X: md2[2])
12
-
13
- md3 = MotionSetY.regexp.match(context.look_next_line)
14
- process_motion_set_y(context, block, md3) if md3
15
-
10
+ add_character_method_call_block(context, md2[1], new, X: md2[2])
16
11
  true
17
12
  end
18
-
19
- def self.process_motion_set_y(context, block, md)
20
- if block.character == get_character(context, md[1])
21
- process_value_string(context, block, md[2], :Y)
22
- context.next_line
23
- end
24
- rescue
25
- return
26
- end
27
- private_class_method :process_motion_set_y
28
-
29
- def type
30
- if @values.key?(:Y)
31
- 'motion_set_x_y'
32
- else
33
- super
34
- end
35
- end
36
13
  end
37
14
  end
38
15
  end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class MotionSetXY < CharacterMethodCall
5
+ blocknize '^\s*' + CHAR_RE +
6
+ 'position\s*=\s*\[\s*(\S+)\s*,\s*(\S+)\s*\]\s*$',
7
+ statement: true, inline: true
8
+
9
+ def self.process_match_data(md, context)
10
+ md2 = regexp.match(md[type])
11
+ add_character_method_call_block(context, md2[1], new,
12
+ X: md2[2], Y: md2[3])
13
+ true
14
+ end
15
+
16
+ def type
17
+ 'motion_set_x_y'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -4,6 +4,7 @@ require 'tempfile'
4
4
  require 'open3'
5
5
  require 'digest/sha2'
6
6
  require 'bundler'
7
+ require 'smalruby_editor'
7
8
  silence_warnings do
8
9
  require_relative 'concerns/ruby_to_block'
9
10
  end
@@ -72,13 +73,15 @@ class SourceCode < ActiveRecord::Base
72
73
  end
73
74
 
74
75
  def ruby_cmd
75
- path = Pathname('rsdl').expand_path(RbConfig::CONFIG['bindir'])
76
- if path.exist?
77
- path
78
- else
79
- Pathname(RbConfig::CONFIG['RUBY_INSTALL_NAME'])
80
- .expand_path(RbConfig::CONFIG['bindir'])
76
+ if SmalrubyEditor.osx?
77
+ dirs = [RbConfig::CONFIG['bindir']] + ENV['PATH'].split(';')
78
+ dirs.each do |dir|
79
+ path = Pathname('rsdl').expand_path(dir)
80
+ return path if path.exist?
81
+ end
81
82
  end
83
+ Pathname(RbConfig::CONFIG['RUBY_INSTALL_NAME'])
84
+ .expand_path(RbConfig::CONFIG['bindir'])
82
85
  end
83
86
 
84
87
  def open3_capture3_ruby_c
@@ -41,7 +41,9 @@
41
41
  .attributes
42
42
  X: {{- get('x') }} Y: {{- get('y') }}
43
43
  %br
44
- 向き: {{- get('angle') }}°
44
+ 向き:
45
+ %i{class: "{{- rotationStyleIconName() }}"}
46
+ {{- get('angle') }}°
45
47
 
46
48
  %a.add-block-button
47
49
  %i.icon-folder-close-alt