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.
- checksums.yaml +4 -4
- data/README.rdoc +16 -1
- data/app/assets/javascripts/blocks/character.js.coffee.erb +8 -1
- data/app/assets/javascripts/blocks/hardware.js.coffee.erb +59 -7
- data/app/assets/javascripts/blocks/motion.js.coffee.erb +1 -2
- data/app/assets/javascripts/models/character.js.coffee +27 -0
- data/app/assets/javascripts/smalruby.js.coffee +4 -0
- data/app/assets/javascripts/views/character_modal_view.js.coffee +22 -1
- data/app/assets/javascripts/views/character_selector_view.js.coffee +7 -6
- data/app/assets/stylesheets/application.css +8 -0
- data/app/assets/stylesheets/editor.css.scss +15 -5
- data/app/controllers/application_controller.rb +4 -7
- data/app/models/concerns/ruby_to_block/block/character.rb +14 -6
- data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car.rb +1 -1
- data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_commands.rb +15 -0
- data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_run.rb +19 -0
- data/app/models/concerns/ruby_to_block/block/motion_set_x.rb +1 -24
- data/app/models/concerns/ruby_to_block/block/motion_set_x_y.rb +21 -0
- data/app/models/source_code.rb +9 -6
- data/app/views/editor/_block_tab.html.haml +3 -1
- data/app/views/editor/_character_modal.html.haml +14 -5
- data/app/views/editor/_toolbox.html.haml +91 -78
- data/bin/smalruby-editor +15 -0
- data/lib/smalruby_editor/version.rb +1 -1
- data/lib/smalruby_editor.rb +39 -4
- data/public/assets/{application-51ab300acd1779bfba20b099e7000b7e.css → application-7f560d8d6d224f87269691c57ca9a376.css} +23 -9
- data/public/assets/{application-51ab300acd1779bfba20b099e7000b7e.css.gz → application-7f560d8d6d224f87269691c57ca9a376.css.gz} +0 -0
- data/public/assets/{application-dc485e2270d6c5fce20c149d1e2c4f8d.js → application-842ac8f5aa3fcc87bbb0e8b3a0fef5d7.js} +148 -21
- data/public/assets/{application-dc485e2270d6c5fce20c149d1e2c4f8d.js.gz → application-842ac8f5aa3fcc87bbb0e8b3a0fef5d7.js.gz} +0 -0
- data/public/assets/manifest-332a5a1668194028b55103e0ea45c054.json +1 -1
- data/smalruby-editor.gemspec +1 -1
- data/spec/acceptance/block_mode/blocks/motion/set_x_y.feature +2 -4
- data/spec/lib/smalruby_editor_spec.rb +12 -0
- data/spec/models/concerns/ruby_to_block/block/hardware_spec.rb +90 -10
- data/spec/models/concerns/ruby_to_block/block/motion_spec.rb +3 -6
- metadata +11 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 110fbf90c4792bd8f54a5186633e8ffd33b3ed82
|
4
|
+
data.tar.gz: e3cfd0fa9043b7d3420fd9cc7eb129f4374b343e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
#
|
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}
|
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(
|
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_('
|
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
|
-
$('#
|
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, @
|
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
|
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')
|
@@ -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:
|
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:
|
298
|
+
width: 50px;
|
293
299
|
}
|
294
300
|
|
295
301
|
.controls {
|
296
|
-
margin-left:
|
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
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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))"\)
|
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
|
-
|
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
|
data/app/models/source_code.rb
CHANGED
@@ -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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|