smalruby-editor 0.1.20-x86-mingw32 → 0.1.21-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of smalruby-editor might be problematic. Click here for more details.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/app/assets/javascripts/blocks/character.js.coffee.erb +3 -10
  4. data/app/assets/javascripts/blocks/control.js.coffee.erb +2 -1
  5. data/app/assets/javascripts/blocks/data.js.coffee.erb +2 -1
  6. data/app/assets/javascripts/blocks/etc.js.coffee.erb +2 -1
  7. data/app/assets/javascripts/blocks/events.js.coffee.erb +5 -4
  8. data/app/assets/javascripts/blocks/field_character.js.coffee.erb +9 -0
  9. data/app/assets/javascripts/blocks/hardware.js.coffee.erb +171 -54
  10. data/app/assets/javascripts/blocks/looks.js.coffee.erb +2 -1
  11. data/app/assets/javascripts/blocks/motion.js.coffee.erb +4 -16
  12. data/app/assets/javascripts/blocks/operators.js.coffee.erb +2 -1
  13. data/app/assets/javascripts/blocks/pen.js.coffee.erb +2 -1
  14. data/app/assets/javascripts/blocks/ruby.js.coffee.erb +2 -1
  15. data/app/assets/javascripts/blocks/sensing.js.coffee.erb +25 -3
  16. data/app/assets/javascripts/blocks/sound.js.coffee.erb +2 -1
  17. data/app/assets/javascripts/generators/ruby.js.coffee.erb +27 -5
  18. data/app/assets/javascripts/models/source_code.js.coffee +20 -7
  19. data/app/assets/javascripts/views/main_menu_view.js.coffee +5 -7
  20. data/app/assets/stylesheets/editor.css.scss +5 -1
  21. data/app/assets/stylesheets/toolbox.css.scss.erb +29 -24
  22. data/app/controllers/source_codes_controller.rb +7 -36
  23. data/app/helpers/editor_helper.rb +9 -0
  24. data/app/models/concerns/ruby_to_block/block/hardware_button_down_or_up.rb +25 -0
  25. data/app/models/concerns/ruby_to_block/block/hardware_button_not_use_pullup.rb +18 -0
  26. data/app/models/concerns/ruby_to_block/block/hardware_motor_driver.rb +22 -0
  27. data/app/models/concerns/ruby_to_block/block/hardware_motor_driver_set_speed.rb +20 -0
  28. data/app/models/concerns/ruby_to_block/block/hardware_motor_driver_speed.rb +24 -0
  29. data/app/models/concerns/ruby_to_block/block/hardware_on_button_down_or_up.rb +19 -0
  30. data/app/models/concerns/ruby_to_block/block/hardware_operation.rb +15 -0
  31. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_set_speed.rb +22 -0
  32. data/app/models/concerns/ruby_to_block/block/hardware_two_wheel_drive_car_speed.rb +26 -0
  33. data/app/models/concerns/ruby_to_block/block/ruby_p.rb +19 -0
  34. data/app/models/concerns/ruby_to_block/block/{motion_reach_wall.rb → sensing_reach_wall.rb} +1 -1
  35. data/app/models/concerns/ruby_to_block/block/text.rb +3 -2
  36. data/app/models/source_code.rb +20 -0
  37. data/app/views/editor/_toolbox.html.haml +84 -63
  38. data/app/views/editor/index.html.haml +1 -1
  39. data/demos/adjust_2wd_car.rb.xml +179 -0
  40. data/demos/car_chase.rb.xml +129 -126
  41. data/demos/hardware_led.rb.xml +7 -4
  42. data/demos/pong.rb.xml +17 -14
  43. data/demos/star.rb.xml +115 -112
  44. data/lib/smalruby_editor/version.rb +3 -3
  45. data/lib/smalruby_editor.rb +16 -0
  46. data/public/assets/{application-c8991557a0789ac1bc9220f409e7f1c1.js → application-734570836cdba680c1568220a51af40f.js} +216 -86
  47. data/public/assets/{application-c8991557a0789ac1bc9220f409e7f1c1.js.gz → application-734570836cdba680c1568220a51af40f.js.gz} +0 -0
  48. data/public/assets/{application-d4fe6c0f970efe8eab9267fd08718d96.css → application-898cb749439fba4ce44cffeac1216201.css} +37 -9
  49. data/public/assets/{application-d4fe6c0f970efe8eab9267fd08718d96.css.gz → application-898cb749439fba4ce44cffeac1216201.css.gz} +0 -0
  50. data/public/assets/manifest-332a5a1668194028b55103e0ea45c054.json +1 -1
  51. data/smalruby-editor.gemspec +2 -1
  52. data/spec/acceptance/block_mode/blocks/events/on_hit.feature +2 -0
  53. data/spec/acceptance/block_mode/blocks/hardware/button_down_or_up.feature +79 -0
  54. data/spec/acceptance/block_mode/blocks/hardware/button_not_use_pullup.feature +61 -0
  55. data/spec/acceptance/block_mode/blocks/hardware/motor_driver.feature +73 -0
  56. data/spec/acceptance/block_mode/blocks/hardware/motor_driver_speed.feature +93 -0
  57. data/spec/acceptance/block_mode/blocks/hardware/on_button_down_or_up.feature +87 -0
  58. data/spec/acceptance/block_mode/blocks/hardware/two_wheel_drive_car_speed.feature +111 -0
  59. data/spec/acceptance/block_mode/blocks/motion/reach_wall.feature +1 -1
  60. data/spec/acceptance/block_mode/blocks/operators/text.feature +38 -0
  61. data/spec/acceptance/block_mode/blocks/sensing/hit.feature +98 -52
  62. data/spec/acceptance/block_mode/blocks/sensing/reach_wall.feature +98 -0
  63. data/spec/acceptance/block_mode/demo.feature +3 -1
  64. data/spec/acceptance/standalone/save.feature +51 -0
  65. data/spec/helpers/editor_helper_spec.rb +20 -0
  66. data/spec/javascripts/models/source_code_spec.coffee +40 -0
  67. data/spec/models/concerns/ruby_to_block/block/hardware_spec.rb +269 -0
  68. data/spec/models/concerns/ruby_to_block/block/motion_spec.rb +1 -1
  69. data/spec/models/concerns/ruby_to_block/block/{motion_reach_wall_spec.rb → sensing_reach_wall_spec.rb} +2 -2
  70. data/spec/models/concerns/ruby_to_block/block/text_spec.rb +39 -0
  71. data/spec/models/concerns/ruby_to_block_spec.rb +2 -2
  72. data/spec/models/source_code_spec.rb +53 -0
  73. data/spec/steps/base_steps.rb +5 -0
  74. metadata +56 -12
  75. data/demos/rgb_led_anode.rb.xml +0 -83
@@ -15,15 +15,28 @@ Smalruby.SourceCode = Backbone.Model.extend
15
15
  filename = '1.rb'
16
16
  @set('filename', filename)
17
17
 
18
- if @get('filename').match(/\.xml$/)
19
- data = Smalruby.dumpXml()
20
- else
21
- if window.blockMode
22
- data = Blockly.Ruby.workspaceToCode()
18
+ unless @get('data')
19
+ if @get('filename').match(/\.xml$/)
20
+ data = Smalruby.dumpXml()
23
21
  else
24
- data = window.textEditor.getSession().getDocument().getValue()
22
+ if window.blockMode
23
+ data = Blockly.Ruby.workspaceToCode()
24
+ else
25
+ data = window.textEditor.getSession().getDocument().getValue()
26
+
27
+ @set('data', data)
25
28
 
26
- @set('data', data)
29
+ getRbxmlFilename: ->
30
+ filename = @get('filename')
31
+ if filename.match(/\.rb\.xml$/)
32
+ filename
33
+ else
34
+ if filename.match(/\.rb$/)
35
+ filename + '.xml'
36
+ else if filename.match(/\.xml$/)
37
+ filename.replace(/\.xml$/, '.rb.xml')
38
+ else
39
+ filename + '.rb.xml'
27
40
 
28
41
  run: ->
29
42
  @post_('run')
@@ -86,9 +86,8 @@ Smalruby.MainMenuView = Backbone.View.extend
86
86
 
87
87
  sourceCode = @getSourceCode()
88
88
 
89
- filename = sourceCode.get('filename')
90
- filename += '.xml' unless filename.match(/\.xml$/)
91
- xmlSourceCode = new Smalruby.SourceCode({ filename: filename })
89
+ xmlSourceCode =
90
+ new Smalruby.SourceCode({ filename: sourceCode.getRbxmlFilename() })
92
91
 
93
92
  clearMessages()
94
93
 
@@ -200,11 +199,10 @@ Smalruby.MainMenuView = Backbone.View.extend
200
199
  $('#filename').focus()
201
200
  return
202
201
 
202
+ sourceCode = @getSourceCode()
203
203
  if window.blockMode
204
- filename += '.xml' unless filename.match(/\.xml$/)
205
- sourceCode = new Smalruby.SourceCode({ filename: filename })
206
- else
207
- sourceCode = @getSourceCode()
204
+ sourceCode =
205
+ new Smalruby.SourceCode({ filename: sourceCode.getRbxmlFilename() })
208
206
 
209
207
  clearMessages()
210
208
 
@@ -13,7 +13,11 @@ $left-pane-width: $character-size + $margin * 2;
13
13
  #messages {
14
14
  position: absolute;
15
15
  right: 20px;
16
- z-index: 9999;
16
+ z-index: 999;
17
+ max-height: 80%;
18
+ overflow: auto;
19
+ bottom: 20px;
20
+ width: 25%;
17
21
  }
18
22
 
19
23
  .left-pane {
@@ -23,30 +23,35 @@
23
23
  }.join
24
24
  end
25
25
 
26
- hues = %w(
27
- 208
28
- 208
29
- 208
30
- 208
31
- 270
32
- 300
33
- 160
34
- 330
35
- 330
36
- 33
37
- 43
38
- 43
39
- 43
40
- 43
41
- 190
42
- 100
43
- 100
44
- 100
45
- 100
46
- 340
47
- 340
48
- 340
49
- ).map(&:to_i)
26
+ require 'smalruby_editor'
27
+ colors = SmalrubyEditor::COLORS
28
+
29
+ hues = [
30
+ colors[:motion],
31
+ colors[:motion],
32
+ colors[:motion],
33
+ colors[:motion],
34
+ colors[:looks],
35
+ colors[:sound],
36
+ colors[:pen],
37
+ colors[:data],
38
+ colors[:data],
39
+ colors[:events],
40
+ colors[:control],
41
+ colors[:control],
42
+ colors[:control],
43
+ colors[:control],
44
+ colors[:sensing],
45
+ colors[:sensing],
46
+ colors[:sensing],
47
+ colors[:operators],
48
+ colors[:operators],
49
+ colors[:operators],
50
+ colors[:operators],
51
+ colors[:etc],
52
+ colors[:etc],
53
+ colors[:etc],
54
+ ]
50
55
 
51
56
  colors = hues.map { |h|
52
57
  [hsv_to_rgb(h, 100, 80), hsv_to_rgb(h, 100, 100)]
@@ -4,50 +4,21 @@ require 'nkf'
4
4
  class SourceCodesController < ApplicationController
5
5
  before_filter :check_whether_standalone, only: [:write, :run, :load_local]
6
6
 
7
- # デモプログラム
8
- DEMO_PROGRAMS =
9
- [
10
- {
11
- title: '車のおいかけっこ',
12
- filename: 'car_chase.rb',
13
- imageUrl: '/smalruby/assets/car2.png',
14
- },
15
- {
16
- title: 'クリックスターだにゃ~',
17
- filename: 'star.rb',
18
- imageUrl: '/smalruby/assets/cat1.png',
19
- },
20
- {
21
- title: 'ピンポンゲーム',
22
- filename: 'pong.rb',
23
- imageUrl: '/smalruby/assets/cat2.png',
24
- },
25
- {
26
- title: 'ライトをぴかっとさせるでよ',
27
- filename: 'hardware_led.rb',
28
- imageUrl: '/smalruby/assets/frog1.png',
29
- },
30
- ]
31
-
32
7
  def index
33
8
  res = {
34
9
  localPrograms: [],
35
10
  demoPrograms: [],
36
11
  }
37
12
  if standalone?
38
- local_program_paths.each do |path|
39
- # TODO: XMLからタイトルを抽出する
40
- # TODO: XMLからキャラクターの画像を抽出する
41
- filename = rb_basename(path)
42
- res[:localPrograms] << {
43
- title: filename,
44
- filename: filename,
45
- }
46
- end
13
+ res[:localPrograms] = local_program_paths.map { |path|
14
+ SourceCode.new(filename: path.basename.to_s, data: path.read).summary
15
+ }
47
16
  end
48
17
 
49
- # TODO: XMLから情報を抽出する
50
- res[:demoPrograms] = DEMO_PROGRAMS
18
+ res[:demoPrograms] = Pathname.glob(Rails.root.join('demos/*.rb.xml')).map {
19
+ |path|
20
+ SourceCode.new(filename: path.basename.to_s, data: path.read).summary
21
+ }
51
22
 
52
23
  render json: res
53
24
  end
@@ -17,6 +17,15 @@ module EditorHelper
17
17
  %(<field name="#{h name}">#{h value}</field>).html_safe
18
18
  end
19
19
 
20
+ # ツールボックスのブロックに対して、PINの入力フィールドの値を設定する
21
+ #
22
+ # @param [String] value ピン
23
+ # @param [String] name 名前
24
+ # @return [String] XML
25
+ def toolbox_pin_field(value, name = 'PIN')
26
+ %(<field name="#{h name}">#{h value}</field>).html_safe
27
+ end
28
+
20
29
  # ツールボックスのブロックに対して、数値型の入力のブロックを設定する
21
30
  #
22
31
  # @param [String] name 入力値の名前
@@ -0,0 +1,25 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareButtonDownOrUp < Value
4
+ include CharacterOperation
5
+ include HardwareOperation
6
+
7
+ blocknize '^\s*' + CHAR_RE +
8
+ 'button\(' + DIO_PIN_RE + '\)\.(down|up)\?\s*$',
9
+ value: true
10
+
11
+ def self.process_match_data(md, context)
12
+ md2 = regexp.match(md[type])
13
+
14
+ character = get_character(context, md2[1])
15
+ return false if context.receiver && context.receiver != character
16
+
17
+ block = new(fields: { PIN: md2[2], DOU: md2[3] })
18
+ context.add_value(block)
19
+ block.character = character
20
+
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareButtonNotUsePullup < CharacterMethodCall
4
+ include HardwareOperation
5
+
6
+ blocknize '^\s*' + CHAR_RE +
7
+ 'button\(' + DIO_PIN_RE + '\)\.not_use_pullup\s*$',
8
+ statement: true
9
+
10
+ def self.process_match_data(md, context)
11
+ md2 = regexp.match(md[type])
12
+ add_character_method_call_block(context, md2[1],
13
+ new(fields: { PIN: md2[2] }))
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareMotorDriver < CharacterMethodCall
5
+ # rubocop:disable LineLength
6
+ blocknize '^\s*' + CHAR_RE +
7
+ 'motor_driver\("(D(?:3|5|6|9|10|11))"\)\.(forward|backward|stop)\s*$',
8
+ statement: true
9
+ # rubocop:enable LineLength
10
+
11
+ attr_accessor :method_name
12
+
13
+ def self.process_match_data(md, context)
14
+ md2 = regexp.match(md[type])
15
+ add_character_method_call_block(context, md2[1],
16
+ new(fields: { PIN: md2[2],
17
+ METHOD: md2[3] }))
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareMotorDriverSetSpeed < CharacterMethodCall
5
+ include HardwareOperation
6
+
7
+ blocknize '^\s*' + CHAR_RE +
8
+ 'motor_driver\(' + PWM_PIN_RE + '\)\.speed\s*=\s*(\S+)\s*$',
9
+ statement: true, inline: true
10
+
11
+ def self.process_match_data(md, context)
12
+ md2 = regexp.match(md[type])
13
+ add_character_method_call_block(context, md2[1],
14
+ new(fields: { PIN: md2[2] }),
15
+ SPEED: md2[3])
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareMotorDriverSpeed < Value
4
+ include CharacterOperation
5
+
6
+ blocknize '^\s*' + CHAR_RE +
7
+ 'motor_driver\("(D(?:3|5|6|9|10|11))"\)\.speed\s*$',
8
+ value: true
9
+
10
+ def self.process_match_data(md, context)
11
+ md2 = regexp.match(md[type])
12
+
13
+ character = get_character(context, md2[1])
14
+ return false if context.receiver && context.receiver != character
15
+
16
+ block = new(fields: { PIN: md2[2] })
17
+ context.add_value(block)
18
+ block.character = character
19
+
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareOnButtonDownOrUp < CharacterEvent
4
+ include HardwareOperation
5
+
6
+ blocknize '^\s*' + CHAR_RE +
7
+ 'on\(:button_(down|up),' + DIO_PIN_RE + '\)\s+' +
8
+ 'do\s*$',
9
+ statement: true, indent: true
10
+
11
+ def self.process_match_data(md, context)
12
+ md2 = regexp.match(md[type])
13
+ add_character_event_blocks(context, md2[1],
14
+ new(fields: { PIN: md2[3], DOU: md2[2] }))
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ # ハードウェアのメソッドや属性に共通するメソッドや定数を定義するモジュール
5
+ module HardwareOperation
6
+ extend ActiveSupport::Concern
7
+
8
+ DIO_PIN_RE = '\s*"(D(?:[2-9]|10|11|12|13))"\s*'
9
+ PWM_PIN_RE = '\s*"(D(?:3|5|6|9|10|11))"\s*'
10
+ AIO_PIN_RE = '\s*"(A[0-5])"\s*'
11
+ TWO_WHEEL_DRIVE_CAR_PIN_RE = '\s*"(D[56])"\s*'
12
+ LOR_RE = '(left|right)'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class HardwareTwoWheelDriveCarSetSpeed < CharacterMethodCall
5
+ include HardwareOperation
6
+
7
+ blocknize '^\s*' + CHAR_RE +
8
+ 'two_wheel_drive_car\(' + TWO_WHEEL_DRIVE_CAR_PIN_RE + '\)\.' +
9
+ LOR_RE + '_speed\s*=\s*(\S+)\s*$',
10
+ statement: true, inline: true
11
+
12
+ def self.process_match_data(md, context)
13
+ md2 = regexp.match(md[type])
14
+ add_character_method_call_block(context, md2[1],
15
+ new(fields: { PIN: md2[2],
16
+ LOR: md2[3] }),
17
+ SPEED: md2[4])
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module RubyToBlock
2
+ module Block
3
+ class HardwareTwoWheelDriveCarSpeed < Value
4
+ include CharacterOperation
5
+ include HardwareOperation
6
+
7
+ blocknize '^\s*' + CHAR_RE +
8
+ 'two_wheel_drive_car\(' + TWO_WHEEL_DRIVE_CAR_PIN_RE + '\)\.' +
9
+ LOR_RE + '_speed\s*$',
10
+ value: true
11
+
12
+ def self.process_match_data(md, context)
13
+ md2 = regexp.match(md[type])
14
+
15
+ character = get_character(context, md2[1])
16
+ return false if context.receiver && context.receiver != character
17
+
18
+ block = new(fields: { PIN: md2[2], LOR: md2[3] })
19
+ context.add_value(block)
20
+ block.character = character
21
+
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RubyToBlock
3
+ module Block
4
+ class RubyP < CharacterMethodCall
5
+ blocknize '^\s*p\((.+)\)\s*$',
6
+ statement: true, inline: true
7
+
8
+ def self.process_match_data(md, context)
9
+ block = new
10
+ context.add_block(block)
11
+
12
+ md2 = regexp.match(md[type])
13
+ process_value_string(context, block, md2[1], :ARG)
14
+
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  module RubyToBlock
3
3
  module Block
4
- class MotionReachWall < Value
4
+ class SensingReachWall < Value
5
5
  include CharacterOperation
6
6
 
7
7
  blocknize '^\s*' + CHAR_RE + 'reach_wall\?\s*$',
@@ -2,11 +2,12 @@
2
2
  module RubyToBlock
3
3
  module Block
4
4
  class Text < Value
5
- blocknize '^\s*"([^"]*)"\s*$', value: true
5
+ blocknize '^\s*"(.*)"\s*$', value: true
6
6
 
7
7
  def self.process_match_data(md, context)
8
8
  md2 = regexp.match(md[type])
9
- context.add_value(new(fields: { TEXT: md2[1] }))
9
+ text = md2[1].gsub(/\\"/, '"')
10
+ context.add_value(new(fields: { TEXT: text }))
10
11
 
11
12
  true
12
13
  end
@@ -64,6 +64,26 @@ class SourceCode < ActiveRecord::Base
64
64
  Digest::SHA256.hexdigest(data)
65
65
  end
66
66
 
67
+ # ソースコードの概要を取得する
68
+ def summary
69
+ res = {}
70
+ if /\.xml\z/ =~ filename
71
+ res[:filename] = filename.sub(/\.xml\z/, '')
72
+
73
+ doc = Nokogiri::HTML.parse(data)
74
+ if (attr = doc.xpath('//character[1]/@costumes').first)
75
+ res[:imageUrl] = "/smalruby/assets/#{attr.value}"
76
+ end
77
+ text = doc.xpath('//block[@type="ruby_comment"][1]' +
78
+ '/field[@name="COMMENT"]/text()').first
79
+ res[:title] = text.to_s if text
80
+ else
81
+ res[:filename] = filename
82
+ end
83
+ res[:title] = filename unless res[:title]
84
+ res
85
+ end
86
+
67
87
  private
68
88
 
69
89
  def validate_filename