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.

Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/.travis.yml +2 -0
  4. data/LEGAL +32 -0
  5. data/Rakefile +1 -1
  6. data/app/assets/demos/default.xml +126 -0
  7. data/app/assets/demos/rgb_led_anode.xml +83 -0
  8. data/app/assets/images/favicon.ico +0 -0
  9. data/app/assets/javascripts/application.js +18 -1
  10. data/app/assets/javascripts/block_mode.js.coffee.erb +10 -0
  11. data/app/assets/javascripts/blocks/blockly.js.coffee.erb +34 -0
  12. data/app/assets/javascripts/blocks/character.js.coffee.erb +76 -0
  13. data/app/assets/javascripts/blocks/control.js.coffee.erb +180 -0
  14. data/app/assets/javascripts/blocks/data.js.coffee.erb +6 -0
  15. data/app/assets/javascripts/blocks/etc.js.coffee.erb +6 -0
  16. data/app/assets/javascripts/blocks/events.js.coffee.erb +82 -0
  17. data/app/assets/javascripts/blocks/hardware.js.coffee.erb +313 -0
  18. data/app/assets/javascripts/blocks/looks.js.coffee.erb +163 -0
  19. data/app/assets/javascripts/blocks/motion.js.coffee.erb +297 -0
  20. data/app/assets/javascripts/blocks/operators.js.coffee.erb +279 -0
  21. data/app/assets/javascripts/blocks/pen.js.coffee.erb +6 -0
  22. data/app/assets/javascripts/blocks/ruby.js.coffee.erb +74 -0
  23. data/app/assets/javascripts/blocks/sensing.js.coffee.erb +241 -0
  24. data/app/assets/javascripts/blocks/sound.js.coffee.erb +75 -0
  25. data/{public/favicon.ico → app/assets/javascripts/collections/.keep} +0 -0
  26. data/app/assets/javascripts/collections/character_set.js.coffee +12 -0
  27. data/app/assets/javascripts/generators/ruby.js.coffee.erb +188 -0
  28. data/app/assets/javascripts/models/.keep +0 -0
  29. data/app/assets/javascripts/models/character.js.coffee +66 -0
  30. data/app/assets/javascripts/models/scene.js.coffee +5 -0
  31. data/app/assets/javascripts/models/source_code.js.coffee +64 -0
  32. data/app/assets/javascripts/routers/.keep +0 -0
  33. data/app/assets/javascripts/ruby_mode.js.coffee.erb +12 -0
  34. data/app/assets/javascripts/smalruby.js.coffee +97 -0
  35. data/app/assets/javascripts/views/.keep +0 -0
  36. data/app/assets/javascripts/views/character_modal_view.js.coffee +148 -0
  37. data/app/assets/javascripts/views/character_selector_view.js.coffee +109 -0
  38. data/app/assets/javascripts/views/main_menu_view.js.coffee +264 -0
  39. data/app/assets/stylesheets/editor.css.scss +318 -2
  40. data/app/assets/stylesheets/toolbox.css.scss.erb +62 -0
  41. data/app/assets/templates/.keep +0 -0
  42. data/app/controllers/application_controller.rb +19 -0
  43. data/app/controllers/editor_controller.rb +4 -0
  44. data/app/controllers/source_codes_controller.rb +8 -2
  45. data/app/helpers/application_helper.rb +1 -0
  46. data/app/helpers/editor_helper.rb +46 -0
  47. data/app/models/source_code.rb +49 -6
  48. data/app/views/editor/_block_tab.html.haml +53 -0
  49. data/app/views/editor/_character_modal.html.haml +53 -0
  50. data/app/views/editor/_toolbox.html.haml +384 -0
  51. data/app/views/editor/demo.html.erb +16 -0
  52. data/app/views/editor/index.html.haml +60 -0
  53. data/app/views/layouts/application.html.erb +7 -0
  54. data/config/application.rb +1 -0
  55. data/config/initializers/teaspoon.rb +79 -0
  56. data/config/routes.rb +4 -0
  57. data/lib/smalruby_editor/version.rb +1 -1
  58. data/lib/tasks/gem.rake +7 -4
  59. data/lib/tasks/release.rake +43 -0
  60. data/public/apple-touch-icon.png +0 -0
  61. data/public/blockly/media/1x1.gif +0 -0
  62. data/public/blockly/media/click.mp3 +0 -0
  63. data/public/blockly/media/click.ogg +0 -0
  64. data/public/blockly/media/click.wav +0 -0
  65. data/public/blockly/media/delete.mp3 +0 -0
  66. data/public/blockly/media/delete.ogg +0 -0
  67. data/public/blockly/media/delete.wav +0 -0
  68. data/public/blockly/media/handclosed.cur +0 -0
  69. data/public/blockly/media/handopen.cur +0 -0
  70. data/public/blockly/media/quote0.png +0 -0
  71. data/public/blockly/media/quote1.png +0 -0
  72. data/public/blockly/media/trashbody.png +0 -0
  73. data/public/blockly/media/trashlid.png +0 -0
  74. data/public/blockly/media/tree.png +0 -0
  75. data/public/browserconfig.xml +1 -0
  76. data/public/large.png +0 -0
  77. data/public/smalruby/assets/ball1.png +0 -0
  78. data/public/smalruby/assets/ball2.png +0 -0
  79. data/public/smalruby/assets/ball3.png +0 -0
  80. data/public/smalruby/assets/ball4.png +0 -0
  81. data/public/smalruby/assets/ball5.png +0 -0
  82. data/public/smalruby/assets/ball6.png +0 -0
  83. data/public/smalruby/assets/car1.png +0 -0
  84. data/public/smalruby/assets/car2.png +0 -0
  85. data/public/smalruby/assets/car3.png +0 -0
  86. data/public/smalruby/assets/car4.png +0 -0
  87. data/public/smalruby/assets/cat1.png +0 -0
  88. data/public/smalruby/assets/cat2.png +0 -0
  89. data/public/smalruby/assets/cat3.png +0 -0
  90. data/public/smalruby/assets/frog1.png +0 -0
  91. data/public/smalruby/assets/piano_do.wav +0 -0
  92. data/public/smalruby/assets/piano_do_2.wav +0 -0
  93. data/public/smalruby/assets/piano_fa.wav +0 -0
  94. data/public/smalruby/assets/piano_mi.wav +0 -0
  95. data/public/smalruby/assets/piano_ra.wav +0 -0
  96. data/public/smalruby/assets/piano_re.wav +0 -0
  97. data/public/smalruby/assets/piano_si.wav +0 -0
  98. data/public/smalruby/assets/piano_so.wav +0 -0
  99. data/public/square.png +0 -0
  100. data/public/tiny.png +0 -0
  101. data/public/wide.png +0 -0
  102. data/smalruby-editor.gemspec +4 -0
  103. data/spec/acceptance/block_mode/blocks/character/new.feature +136 -0
  104. data/spec/acceptance/block_mode/blocks/control/await.feature +20 -0
  105. data/spec/acceptance/block_mode/blocks/control/await_until.feature +39 -0
  106. data/spec/acceptance/block_mode/blocks/control/break.feature +20 -0
  107. data/spec/acceptance/block_mode/blocks/control/if.feature +68 -0
  108. data/spec/acceptance/block_mode/blocks/control/if_else.feature +78 -0
  109. data/spec/acceptance/block_mode/blocks/control/loop.feature +45 -0
  110. data/spec/acceptance/block_mode/blocks/control/next.feature +20 -0
  111. data/spec/acceptance/block_mode/blocks/control/redo.feature +20 -0
  112. data/spec/acceptance/block_mode/blocks/control/sleep.feature +41 -0
  113. data/spec/acceptance/block_mode/blocks/control/times.feature +72 -0
  114. data/spec/acceptance/block_mode/blocks/control/until.feature +68 -0
  115. data/spec/acceptance/block_mode/blocks/events/on_click.feature +75 -0
  116. data/spec/acceptance/block_mode/blocks/events/on_hit.feature +83 -0
  117. data/spec/acceptance/block_mode/blocks/events/on_key_push_or_down.feature +171 -0
  118. data/spec/acceptance/block_mode/blocks/events/on_start.feature +75 -0
  119. data/spec/acceptance/block_mode/blocks/hardware/init_hardware.feature +44 -0
  120. data/spec/acceptance/block_mode/blocks/hardware/led_off.feature +75 -0
  121. data/spec/acceptance/block_mode/blocks/hardware/led_on.feature +75 -0
  122. data/spec/acceptance/block_mode/blocks/hardware/on_sensor_change.feature +81 -0
  123. data/spec/acceptance/block_mode/blocks/hardware/rgb_led_off.feature +81 -0
  124. data/spec/acceptance/block_mode/blocks/hardware/rgb_led_on.feature +87 -0
  125. data/spec/acceptance/block_mode/blocks/hardware/sensor_value.feature +100 -0
  126. data/spec/acceptance/block_mode/blocks/looks/hide.feature +69 -0
  127. data/spec/acceptance/block_mode/blocks/looks/say.feature +106 -0
  128. data/spec/acceptance/block_mode/blocks/looks/show.feature +69 -0
  129. data/spec/acceptance/block_mode/blocks/looks/vanish.feature +69 -0
  130. data/spec/acceptance/block_mode/blocks/motion/change_x_by.feature +81 -0
  131. data/spec/acceptance/block_mode/blocks/motion/change_y_by.feature +81 -0
  132. data/spec/acceptance/block_mode/blocks/motion/move.feature +81 -0
  133. data/spec/acceptance/block_mode/blocks/motion/reach_wall.feature +98 -0
  134. data/spec/acceptance/block_mode/blocks/motion/rotate_left.feature +81 -0
  135. data/spec/acceptance/block_mode/blocks/motion/rotate_right.feature +81 -0
  136. data/spec/acceptance/block_mode/blocks/motion/self_angle.feature +92 -0
  137. data/spec/acceptance/block_mode/blocks/motion/self_x.feature +92 -0
  138. data/spec/acceptance/block_mode/blocks/motion/self_y.feature +92 -0
  139. data/spec/acceptance/block_mode/blocks/motion/set_angle.feature +81 -0
  140. data/spec/acceptance/block_mode/blocks/motion/set_x.feature +81 -0
  141. data/spec/acceptance/block_mode/blocks/motion/set_x_y.feature +95 -0
  142. data/spec/acceptance/block_mode/blocks/motion/set_y.feature +81 -0
  143. data/spec/acceptance/block_mode/blocks/motion/turn.feature +69 -0
  144. data/spec/acceptance/block_mode/blocks/motion/turn_if_reach_wall.feature +69 -0
  145. data/spec/acceptance/block_mode/blocks/sensing/character_property.feature +114 -0
  146. data/spec/acceptance/block_mode/blocks/sensing/hit.feature +110 -0
  147. data/spec/acceptance/block_mode/blocks/sensing/input_key_push_or_down.feature +91 -0
  148. data/spec/acceptance/block_mode/blocks/sensing/input_mouse_pos_x.feature +39 -0
  149. data/spec/acceptance/block_mode/blocks/sensing/input_mouse_pos_y.feature +39 -0
  150. data/spec/acceptance/block_mode/blocks/sensing/input_mouse_push_or_down.feature +91 -0
  151. data/spec/acceptance/block_mode/blocks/sensing/time_now.feature +43 -0
  152. data/spec/acceptance/block_mode/blocks/sound/play.feature +81 -0
  153. data/spec/acceptance/block_mode/demo.feature +49 -0
  154. data/spec/acceptance/{text_editor → ruby_mode}/base.feature +11 -2
  155. data/spec/acceptance/{standalone → ruby_mode}/check.feature +8 -9
  156. data/spec/acceptance/ruby_mode/download.feature +33 -0
  157. data/spec/acceptance/{text_editor → ruby_mode}/load.feature +13 -13
  158. data/spec/acceptance/standalone/run.feature +17 -0
  159. data/spec/acceptance/standalone/save.feature +6 -6
  160. data/spec/helpers/editor_helper_spec.rb +110 -10
  161. data/spec/javascripts/collections/character_set_spec.coffee +41 -0
  162. data/spec/javascripts/models/character_spec.coffee +146 -0
  163. data/spec/javascripts/models/scene_spec.coffee +15 -0
  164. data/spec/javascripts/spec_helper.js +29 -0
  165. data/spec/spec_helper.rb +3 -8
  166. data/spec/steps/block_mode_steps.rb +37 -0
  167. data/spec/steps/global_variable.rb +30 -6
  168. data/spec/steps/text_editor_steps.rb +20 -2
  169. data/spec/teaspoon_env.rb +46 -0
  170. data/vendor/assets/javascripts/blockly/blockly_compressed.js +992 -0
  171. data/vendor/assets/javascripts/blockly/blocks_compressed.js +129 -0
  172. data/vendor/assets/javascripts/blockly/msg/js/ja.js +377 -0
  173. data/vendor/assets/javascripts/jquery.blockUI.js +619 -0
  174. metadata +290 -23
  175. data/app/assets/javascripts/editor.js.coffee.erb +0 -137
  176. data/app/views/editor/index.html.erb +0 -22
  177. data/spec/acceptance/text_editor/check.feature +0 -29
  178. data/spec/acceptance/text_editor/save.feature +0 -34
  179. 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]
@@ -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,5 @@
1
+ Smalruby.Scene = Backbone.Model.extend
2
+ defaults:
3
+ width: 640
4
+ height: 480
5
+ color: 'black'
@@ -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()