smalruby-editor 0.0.12 → 0.1.0
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/.rubocop.yml +5 -0
- data/.travis.yml +2 -0
- data/LEGAL +32 -0
- data/Rakefile +1 -1
- data/app/assets/demos/default.xml +126 -0
- data/app/assets/demos/rgb_led_anode.xml +83 -0
- data/app/assets/images/favicon.ico +0 -0
- data/app/assets/javascripts/application.js +18 -1
- data/app/assets/javascripts/block_mode.js.coffee.erb +10 -0
- data/app/assets/javascripts/blocks/blockly.js.coffee.erb +34 -0
- data/app/assets/javascripts/blocks/character.js.coffee.erb +76 -0
- data/app/assets/javascripts/blocks/control.js.coffee.erb +180 -0
- data/app/assets/javascripts/blocks/data.js.coffee.erb +6 -0
- data/app/assets/javascripts/blocks/etc.js.coffee.erb +6 -0
- data/app/assets/javascripts/blocks/events.js.coffee.erb +82 -0
- data/app/assets/javascripts/blocks/hardware.js.coffee.erb +313 -0
- data/app/assets/javascripts/blocks/looks.js.coffee.erb +163 -0
- data/app/assets/javascripts/blocks/motion.js.coffee.erb +297 -0
- data/app/assets/javascripts/blocks/operators.js.coffee.erb +279 -0
- data/app/assets/javascripts/blocks/pen.js.coffee.erb +6 -0
- data/app/assets/javascripts/blocks/ruby.js.coffee.erb +74 -0
- data/app/assets/javascripts/blocks/sensing.js.coffee.erb +241 -0
- data/app/assets/javascripts/blocks/sound.js.coffee.erb +75 -0
- data/{public/favicon.ico → app/assets/javascripts/collections/.keep} +0 -0
- data/app/assets/javascripts/collections/character_set.js.coffee +12 -0
- data/app/assets/javascripts/generators/ruby.js.coffee.erb +188 -0
- data/app/assets/javascripts/models/.keep +0 -0
- data/app/assets/javascripts/models/character.js.coffee +66 -0
- data/app/assets/javascripts/models/scene.js.coffee +5 -0
- data/app/assets/javascripts/models/source_code.js.coffee +64 -0
- data/app/assets/javascripts/routers/.keep +0 -0
- data/app/assets/javascripts/ruby_mode.js.coffee.erb +12 -0
- data/app/assets/javascripts/smalruby.js.coffee +97 -0
- data/app/assets/javascripts/views/.keep +0 -0
- data/app/assets/javascripts/views/character_modal_view.js.coffee +148 -0
- data/app/assets/javascripts/views/character_selector_view.js.coffee +109 -0
- data/app/assets/javascripts/views/main_menu_view.js.coffee +264 -0
- data/app/assets/stylesheets/editor.css.scss +318 -2
- data/app/assets/stylesheets/toolbox.css.scss.erb +62 -0
- data/app/assets/templates/.keep +0 -0
- data/app/controllers/application_controller.rb +19 -0
- data/app/controllers/editor_controller.rb +4 -0
- data/app/controllers/source_codes_controller.rb +8 -2
- data/app/helpers/application_helper.rb +1 -0
- data/app/helpers/editor_helper.rb +46 -0
- data/app/models/source_code.rb +49 -6
- data/app/views/editor/_block_tab.html.haml +53 -0
- data/app/views/editor/_character_modal.html.haml +53 -0
- data/app/views/editor/_toolbox.html.haml +384 -0
- data/app/views/editor/demo.html.erb +16 -0
- data/app/views/editor/index.html.haml +60 -0
- data/app/views/layouts/application.html.erb +7 -0
- data/config/application.rb +1 -0
- data/config/initializers/teaspoon.rb +79 -0
- data/config/routes.rb +4 -0
- data/lib/smalruby_editor/version.rb +1 -1
- data/lib/tasks/gem.rake +7 -4
- data/lib/tasks/release.rake +43 -0
- data/public/apple-touch-icon.png +0 -0
- data/public/blockly/media/1x1.gif +0 -0
- data/public/blockly/media/click.mp3 +0 -0
- data/public/blockly/media/click.ogg +0 -0
- data/public/blockly/media/click.wav +0 -0
- data/public/blockly/media/delete.mp3 +0 -0
- data/public/blockly/media/delete.ogg +0 -0
- data/public/blockly/media/delete.wav +0 -0
- data/public/blockly/media/handclosed.cur +0 -0
- data/public/blockly/media/handopen.cur +0 -0
- data/public/blockly/media/quote0.png +0 -0
- data/public/blockly/media/quote1.png +0 -0
- data/public/blockly/media/trashbody.png +0 -0
- data/public/blockly/media/trashlid.png +0 -0
- data/public/blockly/media/tree.png +0 -0
- data/public/browserconfig.xml +1 -0
- data/public/large.png +0 -0
- data/public/smalruby/assets/ball1.png +0 -0
- data/public/smalruby/assets/ball2.png +0 -0
- data/public/smalruby/assets/ball3.png +0 -0
- data/public/smalruby/assets/ball4.png +0 -0
- data/public/smalruby/assets/ball5.png +0 -0
- data/public/smalruby/assets/ball6.png +0 -0
- data/public/smalruby/assets/car1.png +0 -0
- data/public/smalruby/assets/car2.png +0 -0
- data/public/smalruby/assets/car3.png +0 -0
- data/public/smalruby/assets/car4.png +0 -0
- data/public/smalruby/assets/cat1.png +0 -0
- data/public/smalruby/assets/cat2.png +0 -0
- data/public/smalruby/assets/cat3.png +0 -0
- data/public/smalruby/assets/frog1.png +0 -0
- data/public/smalruby/assets/piano_do.wav +0 -0
- data/public/smalruby/assets/piano_do_2.wav +0 -0
- data/public/smalruby/assets/piano_fa.wav +0 -0
- data/public/smalruby/assets/piano_mi.wav +0 -0
- data/public/smalruby/assets/piano_ra.wav +0 -0
- data/public/smalruby/assets/piano_re.wav +0 -0
- data/public/smalruby/assets/piano_si.wav +0 -0
- data/public/smalruby/assets/piano_so.wav +0 -0
- data/public/square.png +0 -0
- data/public/tiny.png +0 -0
- data/public/wide.png +0 -0
- data/smalruby-editor.gemspec +4 -0
- data/spec/acceptance/block_mode/blocks/character/new.feature +136 -0
- data/spec/acceptance/block_mode/blocks/control/await.feature +20 -0
- data/spec/acceptance/block_mode/blocks/control/await_until.feature +39 -0
- data/spec/acceptance/block_mode/blocks/control/break.feature +20 -0
- data/spec/acceptance/block_mode/blocks/control/if.feature +68 -0
- data/spec/acceptance/block_mode/blocks/control/if_else.feature +78 -0
- data/spec/acceptance/block_mode/blocks/control/loop.feature +45 -0
- data/spec/acceptance/block_mode/blocks/control/next.feature +20 -0
- data/spec/acceptance/block_mode/blocks/control/redo.feature +20 -0
- data/spec/acceptance/block_mode/blocks/control/sleep.feature +41 -0
- data/spec/acceptance/block_mode/blocks/control/times.feature +72 -0
- data/spec/acceptance/block_mode/blocks/control/until.feature +68 -0
- data/spec/acceptance/block_mode/blocks/events/on_click.feature +75 -0
- data/spec/acceptance/block_mode/blocks/events/on_hit.feature +83 -0
- data/spec/acceptance/block_mode/blocks/events/on_key_push_or_down.feature +171 -0
- data/spec/acceptance/block_mode/blocks/events/on_start.feature +75 -0
- data/spec/acceptance/block_mode/blocks/hardware/init_hardware.feature +44 -0
- data/spec/acceptance/block_mode/blocks/hardware/led_off.feature +75 -0
- data/spec/acceptance/block_mode/blocks/hardware/led_on.feature +75 -0
- data/spec/acceptance/block_mode/blocks/hardware/on_sensor_change.feature +81 -0
- data/spec/acceptance/block_mode/blocks/hardware/rgb_led_off.feature +81 -0
- data/spec/acceptance/block_mode/blocks/hardware/rgb_led_on.feature +87 -0
- data/spec/acceptance/block_mode/blocks/hardware/sensor_value.feature +100 -0
- data/spec/acceptance/block_mode/blocks/looks/hide.feature +69 -0
- data/spec/acceptance/block_mode/blocks/looks/say.feature +106 -0
- data/spec/acceptance/block_mode/blocks/looks/show.feature +69 -0
- data/spec/acceptance/block_mode/blocks/looks/vanish.feature +69 -0
- data/spec/acceptance/block_mode/blocks/motion/change_x_by.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/change_y_by.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/move.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/reach_wall.feature +98 -0
- data/spec/acceptance/block_mode/blocks/motion/rotate_left.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/rotate_right.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/self_angle.feature +92 -0
- data/spec/acceptance/block_mode/blocks/motion/self_x.feature +92 -0
- data/spec/acceptance/block_mode/blocks/motion/self_y.feature +92 -0
- data/spec/acceptance/block_mode/blocks/motion/set_angle.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/set_x.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/set_x_y.feature +95 -0
- data/spec/acceptance/block_mode/blocks/motion/set_y.feature +81 -0
- data/spec/acceptance/block_mode/blocks/motion/turn.feature +69 -0
- data/spec/acceptance/block_mode/blocks/motion/turn_if_reach_wall.feature +69 -0
- data/spec/acceptance/block_mode/blocks/sensing/character_property.feature +114 -0
- data/spec/acceptance/block_mode/blocks/sensing/hit.feature +110 -0
- data/spec/acceptance/block_mode/blocks/sensing/input_key_push_or_down.feature +91 -0
- data/spec/acceptance/block_mode/blocks/sensing/input_mouse_pos_x.feature +39 -0
- data/spec/acceptance/block_mode/blocks/sensing/input_mouse_pos_y.feature +39 -0
- data/spec/acceptance/block_mode/blocks/sensing/input_mouse_push_or_down.feature +91 -0
- data/spec/acceptance/block_mode/blocks/sensing/time_now.feature +43 -0
- data/spec/acceptance/block_mode/blocks/sound/play.feature +81 -0
- data/spec/acceptance/block_mode/demo.feature +49 -0
- data/spec/acceptance/{text_editor → ruby_mode}/base.feature +11 -2
- data/spec/acceptance/{standalone → ruby_mode}/check.feature +8 -9
- data/spec/acceptance/ruby_mode/download.feature +33 -0
- data/spec/acceptance/{text_editor → ruby_mode}/load.feature +13 -13
- data/spec/acceptance/standalone/run.feature +17 -0
- data/spec/acceptance/standalone/save.feature +6 -6
- data/spec/helpers/editor_helper_spec.rb +110 -10
- data/spec/javascripts/collections/character_set_spec.coffee +41 -0
- data/spec/javascripts/models/character_spec.coffee +146 -0
- data/spec/javascripts/models/scene_spec.coffee +15 -0
- data/spec/javascripts/spec_helper.js +29 -0
- data/spec/spec_helper.rb +3 -8
- data/spec/steps/block_mode_steps.rb +37 -0
- data/spec/steps/global_variable.rb +30 -6
- data/spec/steps/text_editor_steps.rb +20 -2
- data/spec/teaspoon_env.rb +46 -0
- data/vendor/assets/javascripts/blockly/blockly_compressed.js +992 -0
- data/vendor/assets/javascripts/blockly/blocks_compressed.js +129 -0
- data/vendor/assets/javascripts/blockly/msg/js/ja.js +377 -0
- data/vendor/assets/javascripts/jquery.blockUI.js +619 -0
- metadata +290 -23
- data/app/assets/javascripts/editor.js.coffee.erb +0 -137
- data/app/views/editor/index.html.erb +0 -22
- data/spec/acceptance/text_editor/check.feature +0 -29
- data/spec/acceptance/text_editor/save.feature +0 -34
- data/spec/support/assets.rb +0 -18
@@ -0,0 +1,75 @@
|
|
1
|
+
# 「音」ジャンル
|
2
|
+
|
3
|
+
<%
|
4
|
+
category = 'sound'
|
5
|
+
color = 296
|
6
|
+
%>
|
7
|
+
|
8
|
+
# [▼プリセット音声]
|
9
|
+
<% n = "#{category}_preset_sounds" %>
|
10
|
+
Blockly.Blocks['<%= n %>'] =
|
11
|
+
init: ()->
|
12
|
+
sounds = [
|
13
|
+
['ピアノのド', 'piano_do.wav'],
|
14
|
+
['ピアノのレ', 'piano_re.wav'],
|
15
|
+
['ピアノのミ', 'piano_mi.wav'],
|
16
|
+
['ピアノのファ', 'piano_fa.wav'],
|
17
|
+
['ピアノのソ', 'piano_so.wav'],
|
18
|
+
['ピアノのラ', 'piano_ra.wav'],
|
19
|
+
['ピアノのシ', 'piano_si.wav'],
|
20
|
+
['ピアノの高いド', 'piano_do_2.wav'],
|
21
|
+
]
|
22
|
+
@setHelpUrl('')
|
23
|
+
@setColour(<%= color %>)
|
24
|
+
@appendDummyInput().appendField(new Blockly.FieldDropdown(sounds), 'NAME')
|
25
|
+
@setOutput(true, 'String')
|
26
|
+
@setTooltip('')
|
27
|
+
|
28
|
+
Blockly.Ruby['<%= n %>'] = (block) ->
|
29
|
+
code = Blockly.Ruby.quote_(@getFieldValue('NAME'))
|
30
|
+
[code, Blockly.Ruby.ORDER_ATOMIC]
|
31
|
+
|
32
|
+
# [▼]の音を鳴らす
|
33
|
+
<% n = "#{category}_play" %>
|
34
|
+
Blockly.Blocks['<%= n %>'] =
|
35
|
+
init: ()->
|
36
|
+
@setHelpUrl('')
|
37
|
+
@setColour(<%= color %>)
|
38
|
+
@appendValueInput('NAME').setCheck('String')
|
39
|
+
@appendDummyInput().appendField('の音を鳴らす')
|
40
|
+
@setInputsInline(true)
|
41
|
+
@setPreviousStatement(true)
|
42
|
+
@setNextStatement(true)
|
43
|
+
@setTooltip('')
|
44
|
+
|
45
|
+
Blockly.Ruby['<%= n %>'] = (block) ->
|
46
|
+
arg = Blockly.Ruby.valueToCode(@, 'NAME', Blockly.Ruby.ORDER_NONE) || ''
|
47
|
+
Blockly.Ruby.characterMethodCall_('play', "name: #{arg}")
|
48
|
+
|
49
|
+
# すべての音を止める
|
50
|
+
<% n = "#{category}_stop" %>
|
51
|
+
Blockly.Blocks['<%= n %>'] =
|
52
|
+
init: ()->
|
53
|
+
@setHelpUrl('')
|
54
|
+
@setColour(<%= color %>)
|
55
|
+
@appendDummyInput()
|
56
|
+
.appendField('すべての音を止める')
|
57
|
+
@setPreviousStatement(true)
|
58
|
+
@setNextStatement(true)
|
59
|
+
@setTooltip('')
|
60
|
+
|
61
|
+
Blockly.Ruby['<%= n %>'] = (block) ->
|
62
|
+
'stop\n'
|
63
|
+
|
64
|
+
# 変数:ボリューム
|
65
|
+
<% n = "#{category}_volume" %>
|
66
|
+
Blockly.Blocks['<%= n %>'] =
|
67
|
+
init: ()->
|
68
|
+
@setHelpUrl('')
|
69
|
+
@setColour(<%= color %>)
|
70
|
+
@appendDummyInput().appendField('ボリューム')
|
71
|
+
@setOutput(true, 'Number')
|
72
|
+
@setTooltip('')
|
73
|
+
|
74
|
+
Blockly.Ruby['<%= n %>'] = (block) ->
|
75
|
+
['volume', Blockly.Ruby.ORDER_ATOMIC]
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# キャラクターの一覧を表現するコレクション
|
2
|
+
Smalruby.CharacterSet = Backbone.Collection.extend
|
3
|
+
model: Smalruby.Character
|
4
|
+
|
5
|
+
uniqueName: (costume = Smalruby.Character.PRESET_COSTUMES[0])->
|
6
|
+
prefix = costume.substring(costume.lastIndexOf('/') + 1).replace(/\.[^.]*$/, '').replace(/[\d]*$/, '')
|
7
|
+
max = 0
|
8
|
+
r = new RegExp('^' + prefix + '(\\d+)$')
|
9
|
+
_.each @pluck('name'), (name) ->
|
10
|
+
if name.match(r)
|
11
|
+
max = _.max([max, parseInt(RegExp.$1)])
|
12
|
+
"#{prefix}#{max + 1}"
|
@@ -0,0 +1,188 @@
|
|
1
|
+
Blockly.Ruby = new Blockly.Generator('Ruby')
|
2
|
+
|
3
|
+
Blockly.Ruby.addReservedWords '
|
4
|
+
BEGIN class ensure nil self when
|
5
|
+
END def false not super while
|
6
|
+
alias defined? for or then yield
|
7
|
+
and do if redo true __LINE__
|
8
|
+
begin else in rescue undef __FILE__
|
9
|
+
break elsif module retry unless __ENCODING__
|
10
|
+
case end next return until
|
11
|
+
'.split(/\s+/)
|
12
|
+
|
13
|
+
# TODO: 確認すること
|
14
|
+
Blockly.Ruby.ORDER_ATOMIC = 0 # 0 "" ...
|
15
|
+
Blockly.Ruby.ORDER_COLLECTION = 1 # tuples, lists, dictionaries
|
16
|
+
Blockly.Ruby.ORDER_STRING_CONVERSION = 1 # `expression...`
|
17
|
+
Blockly.Ruby.ORDER_MEMBER = 2 # . []
|
18
|
+
Blockly.Ruby.ORDER_FUNCTION_CALL = 2 # ()
|
19
|
+
Blockly.Ruby.ORDER_EXPONENTIATION = 3 # **
|
20
|
+
Blockly.Ruby.ORDER_UNARY_SIGN = 4 # + -
|
21
|
+
Blockly.Ruby.ORDER_BITWISE_NOT = 4 # ~
|
22
|
+
Blockly.Ruby.ORDER_MULTIPLICATIVE = 5 # * / // %
|
23
|
+
Blockly.Ruby.ORDER_ADDITIVE = 6 # + -
|
24
|
+
Blockly.Ruby.ORDER_BITWISE_SHIFT = 7 # << >>
|
25
|
+
Blockly.Ruby.ORDER_BITWISE_AND = 8 # &
|
26
|
+
Blockly.Ruby.ORDER_BITWISE_XOR = 9 # ^
|
27
|
+
Blockly.Ruby.ORDER_BITWISE_OR = 10 # |
|
28
|
+
Blockly.Ruby.ORDER_RELATIONAL = 11 # in, not in, is, is not,
|
29
|
+
# <, <=, >, >=, <>, !=, ==
|
30
|
+
Blockly.Ruby.ORDER_LOGICAL_NOT = 12 # not
|
31
|
+
Blockly.Ruby.ORDER_LOGICAL_AND = 13 # and
|
32
|
+
Blockly.Ruby.ORDER_LOGICAL_OR = 14 # or
|
33
|
+
Blockly.Ruby.ORDER_CONDITIONAL = 15 # if else
|
34
|
+
Blockly.Ruby.ORDER_LAMBDA = 16 # lambda
|
35
|
+
Blockly.Ruby.ORDER_NONE = 99 # (...)
|
36
|
+
|
37
|
+
Blockly.Ruby.INFINITE_LOOP_TRAP = null
|
38
|
+
|
39
|
+
Blockly.Ruby.init = ->
|
40
|
+
@definitions_ = Object.create(null)
|
41
|
+
|
42
|
+
if Blockly.Variables
|
43
|
+
if !@variableDB_
|
44
|
+
@variableDB_ = new Blockly.Names(Blockly.Ruby.RESERVED_WORDS_)
|
45
|
+
else
|
46
|
+
@variableDB_.reset()
|
47
|
+
|
48
|
+
@definitions_['require_smalruby'] = 'require "smalruby"'
|
49
|
+
@definitions_['receiver_stack'] = ['main']
|
50
|
+
@definitions_['character_stack'] = []
|
51
|
+
|
52
|
+
Blockly.Ruby.characterStack = ->
|
53
|
+
@definitions_['character_stack']
|
54
|
+
|
55
|
+
Blockly.Ruby.character = ->
|
56
|
+
_.last(@characterStack())
|
57
|
+
|
58
|
+
Blockly.Ruby.receiverStack = ->
|
59
|
+
@definitions_['receiver_stack']
|
60
|
+
|
61
|
+
Blockly.Ruby.receiver = ->
|
62
|
+
_.last(@receiverStack())
|
63
|
+
|
64
|
+
Blockly.Ruby.receiverName = (options = {}) ->
|
65
|
+
opts =
|
66
|
+
object: Blockly.Ruby.character()
|
67
|
+
dropSelf: true
|
68
|
+
_.extend(opts, options)
|
69
|
+
r = @receiver()
|
70
|
+
if r == opts.object
|
71
|
+
if opts.dropSelf
|
72
|
+
''
|
73
|
+
else
|
74
|
+
'self.'
|
75
|
+
else
|
76
|
+
"#{opts.object.get('name')}."
|
77
|
+
|
78
|
+
Blockly.Ruby.cs = Blockly.Ruby.characterStack
|
79
|
+
Blockly.Ruby.cs_ = Blockly.Ruby.characterStack
|
80
|
+
Blockly.Ruby.c = Blockly.Ruby.character
|
81
|
+
Blockly.Ruby.c_ = Blockly.Ruby.character
|
82
|
+
Blockly.Ruby.rs = Blockly.Ruby.receiverStack
|
83
|
+
Blockly.Ruby.rs_ = Blockly.Ruby.receiverStack
|
84
|
+
Blockly.Ruby.r = Blockly.Ruby.r
|
85
|
+
Blockly.Ruby.r_ = Blockly.Ruby.r
|
86
|
+
Blockly.Ruby.rn = Blockly.Ruby.receiverName
|
87
|
+
Blockly.Ruby.rn_ = Blockly.Ruby.receiverName
|
88
|
+
|
89
|
+
Blockly.Ruby.characterMethodCall_ = (method, args, options = {}) ->
|
90
|
+
res = @characterMethodCallInput_(method, args, options)
|
91
|
+
if res[0]
|
92
|
+
"#{res[0]}\n"
|
93
|
+
else
|
94
|
+
''
|
95
|
+
|
96
|
+
Blockly.Ruby.characterMethodCallInput_ = (method, args, options = {}) ->
|
97
|
+
code =
|
98
|
+
if @c_()
|
99
|
+
if args && args.length > 0
|
100
|
+
"#{@rn_(options)}#{method}(#{args})"
|
101
|
+
else
|
102
|
+
"#{@rn_(options)}#{method}"
|
103
|
+
else
|
104
|
+
null
|
105
|
+
[code, @ORDER_FUNCTION_CALL]
|
106
|
+
|
107
|
+
Blockly.Ruby.characterSetVariable_ = (name, val, operator = '=') ->
|
108
|
+
if @c_()
|
109
|
+
"#{@rn_({ dropSelf: false})}#{name} #{operator} #{val}\n"
|
110
|
+
else
|
111
|
+
''
|
112
|
+
|
113
|
+
Blockly.Ruby.characterEvent_ = (block, bodyName, name, arg = null) ->
|
114
|
+
if c = @c_()
|
115
|
+
@rs_().push(c)
|
116
|
+
try
|
117
|
+
body = Blockly.Ruby.statementToCode(block, bodyName) || '\n'
|
118
|
+
finally
|
119
|
+
@rs_().pop()
|
120
|
+
|
121
|
+
if arg
|
122
|
+
arg = ", #{arg}"
|
123
|
+
else
|
124
|
+
arg = ''
|
125
|
+
|
126
|
+
"""
|
127
|
+
|
128
|
+
|
129
|
+
#{@rn_()}on(:#{name}#{arg}) do
|
130
|
+
#{body}end
|
131
|
+
|
132
|
+
"""
|
133
|
+
else
|
134
|
+
''
|
135
|
+
|
136
|
+
Blockly.Ruby.finish = (code) ->
|
137
|
+
requires = []
|
138
|
+
definitions = []
|
139
|
+
for name of Blockly.Ruby.definitions_
|
140
|
+
do (name) ->
|
141
|
+
def = Blockly.Ruby.definitions_[name]
|
142
|
+
if _.isString(def)
|
143
|
+
if def.match(/^require\s*('\S+'|"\S+")/)
|
144
|
+
requires.push(def)
|
145
|
+
else
|
146
|
+
definitions.push(def)
|
147
|
+
|
148
|
+
if definitions.length == 0 && code.length == 0
|
149
|
+
return ''
|
150
|
+
|
151
|
+
allDefs = requires.join('\n') + '\n\n'
|
152
|
+
if definitions.length > 0
|
153
|
+
allDefs += definitions.join('\n')
|
154
|
+
.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n')
|
155
|
+
allDefs + code
|
156
|
+
|
157
|
+
Blockly.Ruby.scrubNakedValue = (line) ->
|
158
|
+
line + '\n'
|
159
|
+
|
160
|
+
Blockly.Ruby.quote_ = (string) ->
|
161
|
+
# TODO: 実装すること
|
162
|
+
# stringに"を含んでいたら、aから順番にstringに含まれるか試して、含ま
|
163
|
+
# れていない文字を使って%Qa...aとしようかな。でも生成したソースコード
|
164
|
+
# の可読性が下がりますね。
|
165
|
+
'\"' + string + '\"'
|
166
|
+
|
167
|
+
Blockly.Ruby.scrub_ = (block, code) ->
|
168
|
+
if code == null
|
169
|
+
return ''
|
170
|
+
|
171
|
+
commentCode = ''
|
172
|
+
if !block.outputConnection || !block.outputConnection.targetConnection
|
173
|
+
comment = block.getCommentText()
|
174
|
+
if comment
|
175
|
+
commentCode += @prefixLines(comment, '# ') + '\n'
|
176
|
+
|
177
|
+
for input in block.inputList
|
178
|
+
do (input) =>
|
179
|
+
if input.type == Blockly.INPUT_VALUE
|
180
|
+
childBlock = input.connection.targetBlock()
|
181
|
+
if childBlock
|
182
|
+
comment = @allNestedComments(childBlock)
|
183
|
+
if comment
|
184
|
+
commentCode += @prefixLines(comment, '# ')
|
185
|
+
|
186
|
+
nextBlock = block.nextConnection && block.nextConnection.targetBlock()
|
187
|
+
nextCode = this.blockToCode(nextBlock)
|
188
|
+
commentCode + code + nextCode
|
File without changes
|
@@ -0,0 +1,66 @@
|
|
1
|
+
Smalruby.Character = Backbone.Model.extend({
|
2
|
+
defaults:
|
3
|
+
name: null
|
4
|
+
costumes: [],
|
5
|
+
costumeIndex: 0
|
6
|
+
x: 0
|
7
|
+
y: 0
|
8
|
+
angle: 0
|
9
|
+
visible: true
|
10
|
+
using: false
|
11
|
+
|
12
|
+
initialize: ->
|
13
|
+
@objects = []
|
14
|
+
if @get('costumes').length == 0
|
15
|
+
@set({ costumes: [Smalruby.Character.PRESET_COSTUMES[0]] })
|
16
|
+
|
17
|
+
link: (object) ->
|
18
|
+
@objects.push(object)
|
19
|
+
@objects = _.uniq(@objects)
|
20
|
+
if @objects.length > 0
|
21
|
+
@set('using', true)
|
22
|
+
|
23
|
+
unlink: (object) ->
|
24
|
+
@objects = _.without(@objects, object)
|
25
|
+
if @objects.length == 0
|
26
|
+
@set('using', false)
|
27
|
+
|
28
|
+
namePrefix: ->
|
29
|
+
Smalruby.Character.costumeToNamePrefix(@get('name'))
|
30
|
+
|
31
|
+
costume: ->
|
32
|
+
@get('costumes')[@get('costumeIndex')]
|
33
|
+
|
34
|
+
costumeUrl: (index = @get('costumeIndex')) ->
|
35
|
+
basename = @get('costumes')[index]
|
36
|
+
if _.indexOf(Smalruby.Character.PRESET_COSTUMES, basename) == -1
|
37
|
+
basename
|
38
|
+
else
|
39
|
+
"/smalruby/assets/#{basename}"
|
40
|
+
|
41
|
+
nextCostume: ->
|
42
|
+
i = @get('costumeIndex') + 1
|
43
|
+
i = 0 if i >= @get('costumes').length
|
44
|
+
@set({ 'costumeIndex': i })
|
45
|
+
i
|
46
|
+
}, {
|
47
|
+
PRESET_COSTUMES: [
|
48
|
+
'car1.png'
|
49
|
+
'car2.png'
|
50
|
+
'car3.png'
|
51
|
+
'car4.png'
|
52
|
+
'ball1.png'
|
53
|
+
'ball2.png'
|
54
|
+
'ball3.png'
|
55
|
+
'ball4.png'
|
56
|
+
'ball5.png'
|
57
|
+
'ball6.png'
|
58
|
+
'cat1.png'
|
59
|
+
'cat2.png'
|
60
|
+
'cat3.png'
|
61
|
+
'frog1.png'
|
62
|
+
]
|
63
|
+
|
64
|
+
costumeToNamePrefix: (costume) ->
|
65
|
+
costume.substring(costume.lastIndexOf('/') + 1).replace(/\.[^.]*$/, '').replace(/[\d]*$/, '')
|
66
|
+
})
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# ソースコードを表現するモデル
|
2
|
+
Smalruby.SourceCode = Backbone.Model.extend
|
3
|
+
defaults:
|
4
|
+
filename: null
|
5
|
+
data: null
|
6
|
+
|
7
|
+
initialize: ->
|
8
|
+
unless @get('filename')
|
9
|
+
filename = Smalruby.Views.MainMenuView.getFilename()
|
10
|
+
if filename.length == 0
|
11
|
+
c = Smalruby.Collections.CharacterSet.first()
|
12
|
+
if c
|
13
|
+
filename = "#{c.get('name')}.rb"
|
14
|
+
else
|
15
|
+
filename = '1.rb'
|
16
|
+
@set('filename', filename)
|
17
|
+
|
18
|
+
if @get('filename').match(/\.xml$/)
|
19
|
+
data = Smalruby.dumpXml()
|
20
|
+
else
|
21
|
+
if window.blockMode
|
22
|
+
data = Blockly.Ruby.workspaceToCode()
|
23
|
+
else
|
24
|
+
data =window.textEditor.getSession().getDocument().getValue()
|
25
|
+
|
26
|
+
@set('data', data)
|
27
|
+
|
28
|
+
run: ->
|
29
|
+
@post_('run')
|
30
|
+
|
31
|
+
check: ->
|
32
|
+
@post_('check')
|
33
|
+
|
34
|
+
save2: ->
|
35
|
+
@post_('')
|
36
|
+
|
37
|
+
write: (force = false) ->
|
38
|
+
action = 'write'
|
39
|
+
action += '?force=1' if force
|
40
|
+
@delete_(action)
|
41
|
+
|
42
|
+
post_: (action) ->
|
43
|
+
dfr = $.Deferred()
|
44
|
+
$.ajax
|
45
|
+
url: "/source_codes/#{action}"
|
46
|
+
type: 'POST'
|
47
|
+
data:
|
48
|
+
source_code:
|
49
|
+
filename: @get('filename')
|
50
|
+
data: @get('data')
|
51
|
+
dataType: 'json'
|
52
|
+
success: (data, textStatus, jqXHR) -> dfr.resolve(data)
|
53
|
+
error: dfr.reject
|
54
|
+
dfr.promise()
|
55
|
+
|
56
|
+
delete_: (action) ->
|
57
|
+
dfr = $.Deferred()
|
58
|
+
$.ajax
|
59
|
+
url: "/source_codes/#{action}"
|
60
|
+
type: 'DELETE'
|
61
|
+
dataType: 'json'
|
62
|
+
success: (data, textStatus, jqXHR) -> dfr.resolve(data)
|
63
|
+
error: dfr.reject
|
64
|
+
dfr.promise()
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
$ ->
|
2
|
+
window.textEditor = textEditor = ace.edit('text-editor')
|
3
|
+
textEditor.setTheme('ace/theme/clouds')
|
4
|
+
textEditor.setShowInvisibles(true)
|
5
|
+
textEditor.gotoLine(0, 0)
|
6
|
+
textEditor.on 'change', (e) ->
|
7
|
+
window.changed = true
|
8
|
+
|
9
|
+
session = textEditor.getSession()
|
10
|
+
session.setMode('ace/mode/ruby')
|
11
|
+
session.setTabSize(2)
|
12
|
+
session.setUseSoftTabs(true)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
window.SmalrubyEditor = {}
|
2
|
+
window.changed = false
|
3
|
+
window.textEditor = null
|
4
|
+
window.blockMode = true
|
5
|
+
|
6
|
+
window.successMessage = (title, msg = '', selector = '#messages') ->
|
7
|
+
html = $('<div class="alert alert-success" style="display: none">')
|
8
|
+
.append("<h4><i class=\"icon-star\"></i>#{title}</h4>")
|
9
|
+
.append(msg)
|
10
|
+
$(selector).append(html)
|
11
|
+
html.fadeIn('slow')
|
12
|
+
.delay(3000)
|
13
|
+
.fadeOut('slow')
|
14
|
+
|
15
|
+
window.errorMessage = (msg, selector = '#messages') ->
|
16
|
+
html = $('<div class="alert alert-error" style="display: none">')
|
17
|
+
.append('<button type="button" class="close" data-dismiss="alert">×</button>')
|
18
|
+
.append('<h4><i class="icon-exclamation-sign"></i>エラー</h4>')
|
19
|
+
.append(msg)
|
20
|
+
$(selector).append(html)
|
21
|
+
html.fadeIn('slow')
|
22
|
+
|
23
|
+
window.Smalruby =
|
24
|
+
Models: {}
|
25
|
+
Collections: {}
|
26
|
+
Views: {}
|
27
|
+
Routers: {}
|
28
|
+
initialize: ->
|
29
|
+
# HACK: Underscoreのテンプレートの<%, %>はHamlと組み合わせたときに
|
30
|
+
# HTML要素の属性がHamlによってエスケープされてしまうため使いにく
|
31
|
+
# い。そこで、それぞれ{{, }}に変更する。
|
32
|
+
_.extend(_.templateSettings, {
|
33
|
+
escape: /{{-([\s\S]+?)}}/
|
34
|
+
evaluate: /{{([\s\S]+?)}}/
|
35
|
+
interpolate: /{{=([\s\S]+?)}}/
|
36
|
+
})
|
37
|
+
|
38
|
+
@Collections.CharacterSet = new Smalruby.CharacterSet()
|
39
|
+
|
40
|
+
@Views.MainMenuView = new Smalruby.MainMenuView()
|
41
|
+
@Views.CharacterSelectorView = new Smalruby.CharacterSelectorView
|
42
|
+
model: @Collections.CharacterSet
|
43
|
+
@Views.CharacterModalView = new Smalruby.CharacterModalView
|
44
|
+
el: $('#character-modal')
|
45
|
+
|
46
|
+
$('a[data-toggle="tab"]').on 'shown', (e) ->
|
47
|
+
if $(e.target).attr('href') == '#block-tab'
|
48
|
+
window.blockMode = true
|
49
|
+
else
|
50
|
+
window.blockMode = false
|
51
|
+
data = Blockly.Ruby.workspaceToCode()
|
52
|
+
if $.trim(data).length > 0
|
53
|
+
window.textEditor.getSession().getDocument().setValue(data)
|
54
|
+
window.textEditor.moveCursorTo(0, 0)
|
55
|
+
window.textEditor.focus()
|
56
|
+
|
57
|
+
Smalruby.downloading = false
|
58
|
+
window.onbeforeunload = (event) ->
|
59
|
+
if !Smalruby.downloading && window.changed
|
60
|
+
return '作成中のプログラムが消えてしまうよ!'
|
61
|
+
else
|
62
|
+
Smalruby.downloading = false
|
63
|
+
return
|
64
|
+
|
65
|
+
loadXml: (data, workspace = Blockly.mainWorkspace) ->
|
66
|
+
xml = Blockly.Xml.textToDom(data)
|
67
|
+
workspace.clear()
|
68
|
+
chars = []
|
69
|
+
i = 0
|
70
|
+
while (xmlChild = xml.childNodes[i])
|
71
|
+
if xmlChild.nodeName.toLowerCase() == 'character'
|
72
|
+
c = new Smalruby.Character
|
73
|
+
name: xmlChild.getAttribute('name')
|
74
|
+
costumes: xmlChild.getAttribute('costumes').split(',')
|
75
|
+
x: parseInt(xmlChild.getAttribute('x'), 10)
|
76
|
+
y: parseInt(xmlChild.getAttribute('y'), 10)
|
77
|
+
angle: parseInt(xmlChild.getAttribute('angle'), 10)
|
78
|
+
chars.push(c)
|
79
|
+
i++
|
80
|
+
Smalruby.Collections.CharacterSet.reset(chars)
|
81
|
+
Blockly.Xml.domToWorkspace(workspace, xml)
|
82
|
+
|
83
|
+
dumpXml: (workspace = Blockly.mainWorkspace, charSet = Smalruby.Collections.CharacterSet) ->
|
84
|
+
xmlDom = Blockly.Xml.workspaceToDom(workspace)
|
85
|
+
blocklyDom = xmlDom.firstChild
|
86
|
+
charSet.each (c) ->
|
87
|
+
e = goog.dom.createDom('character')
|
88
|
+
e.setAttribute('x', c.get('x'))
|
89
|
+
e.setAttribute('y', c.get('y'))
|
90
|
+
e.setAttribute('name', c.get('name'))
|
91
|
+
e.setAttribute('costumes', c.get('costumes').join(','))
|
92
|
+
e.setAttribute('angle', c.get('angle'))
|
93
|
+
xmlDom.insertBefore(e, blocklyDom)
|
94
|
+
Blockly.Xml.domToPrettyText(xmlDom)
|
95
|
+
|
96
|
+
$(document).ready ->
|
97
|
+
Smalruby.initialize()
|