smalruby/smalruby-editor

View on GitHub
app/assets/javascripts/generators/ruby.js.coffee.erb

Summary

Maintainability
Test Coverage
Blockly.Ruby = new Blockly.Generator('Ruby')

Blockly.Ruby.addReservedWords '
BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true     __LINE__
begin    else     in       rescue   undef    __FILE__
break    elsif    module   retry    unless   __ENCODING__
case     end      next     return   until
'.split(/\s+/)

Blockly.Ruby.ORDER_ATOMIC = 0            # 0 "" ...
Blockly.Ruby.ORDER_COLLECTION = 1        # tuples, lists, dictionaries
Blockly.Ruby.ORDER_STRING_CONVERSION = 1 # `expression...`
Blockly.Ruby.ORDER_MEMBER = 2           # ::
Blockly.Ruby.ORDER_INDEX = 3            # []
Blockly.Ruby.ORDER_FUNCTION_CALL = 4    # ()
Blockly.Ruby.ORDER_UNARY_SIGN = 5       # +(単項)  !  ~
Blockly.Ruby.ORDER_EXPONENTIATION = 6   # **
Blockly.Ruby.ORDER_UNARY_MINUS_SIGN = 7 # -(単項)
Blockly.Ruby.ORDER_MULTIPLICATIVE = 8   # *  /  %
Blockly.Ruby.ORDER_ADDITIVE = 9         # +  -
Blockly.Ruby.ORDER_BITWISE_SHIFT = 10   # << >>
Blockly.Ruby.ORDER_BITWISE_AND = 11     # &
Blockly.Ruby.ORDER_BITWISE_XOR = 12     # ^
Blockly.Ruby.ORDER_BITWISE_OR = 12      # |
Blockly.Ruby.ORDER_RELATIONAL = 13      # > >=  < <=
Blockly.Ruby.ORDER_EQUALS = 14          # <=> ==  === !=  =~  !~
Blockly.Ruby.ORDER_LOGICAL_AND = 15     # &&
Blockly.Ruby.ORDER_LOGICAL_OR = 16      # ||
Blockly.Ruby.ORDER_RANGE = 17           # ..  ...
Blockly.Ruby.ORDER_CONDITIONAL = 18     # ?:(条件演算子)
Blockly.Ruby.ORDER_ASSIGNMENT = 19      # =(+=, -= ... )
Blockly.Ruby.ORDER_NOT = 20             # not
Blockly.Ruby.ORDER_AND_OR = 21          # and or
Blockly.Ruby.ORDER_NONE = 99             # (...)

Blockly.Ruby.INFINITE_LOOP_TRAP = null

Blockly.Ruby.init = ->
  @definitions_ = Object.create(null)

  if Blockly.Variables
    if !@variableDB_
      @variableDB_ = new Blockly.Names(Blockly.Ruby.RESERVED_WORDS_)
    else
      @variableDB_.reset()

    @definitions_['require__smalruby'] = 'require "smalruby"'
    @definitions_['receiver_stack'] = ['main']
    @definitions_['character_stack'] = []

Blockly.Ruby.defineCharacter = (c) ->
  name = c.get('name')
  blockName = "character_#{name}"
  if !Blockly.Ruby.definitions_[blockName]
    switch c.get('rotationStyle')
      when 'left_right'
        rotationStyle = ', rotation_style: :left_right'
      when 'none'
        rotationStyle = ', rotation_style: :none'
      else
        rotationStyle = ''
    costumeParam = ['costume: ']
    costumes = (Blockly.Ruby.quote_(costume) for costume in c.costumesWithName())
    if costumes.length > 1
      costumeParam.push("[#{costumes.join(', ')}]")
    else
      costumeParam.push(costumes[0])
    costumeIndex = c.get('costumeIndex')
    if costumeIndex > 0
      costumeParam.push(", costume_index: #{costumeIndex}")
    Blockly.Ruby.definitions_[blockName] =
      "#{name} = Character.new(#{costumeParam.join('')}, x: #{c.get('x')}, y: #{c.get('y')}, angle: #{c.get('angle')}#{rotationStyle})"

Blockly.Ruby.characterStack = ->
  @definitions_['character_stack']

Blockly.Ruby.character = ->
  _.last(@characterStack())

Blockly.Ruby.receiverStack = ->
  @definitions_['receiver_stack']

Blockly.Ruby.receiver = ->
  _.last(@receiverStack())

Blockly.Ruby.receiverName = (options = {}) ->
  opts =
    object: Blockly.Ruby.character()
    dropSelf: true
  _.extend(opts, options)
  r = @receiver()
  if r == opts.object
    if opts.dropSelf
      ''
    else
      'self.'
  else
    "#{opts.object.get('name')}."

Blockly.Ruby.cs = Blockly.Ruby.characterStack
Blockly.Ruby.cs_ = Blockly.Ruby.characterStack
Blockly.Ruby.c = Blockly.Ruby.character
Blockly.Ruby.c_ = Blockly.Ruby.character
Blockly.Ruby.rs = Blockly.Ruby.receiverStack
Blockly.Ruby.rs_ = Blockly.Ruby.receiverStack
Blockly.Ruby.r = Blockly.Ruby.receiver
Blockly.Ruby.r_ = Blockly.Ruby.receiver
Blockly.Ruby.rn = Blockly.Ruby.receiverName
Blockly.Ruby.rn_ = Blockly.Ruby.receiverName

Blockly.Ruby.characterMethodCall_ = (method, args, options = {}) ->
  res = @characterMethodCallInput_(method, args, options)
  if res[0]
    "#{res[0]}\n"
  else
    ''

Blockly.Ruby.characterMethodCallInput_ = (method, args, options = {}) ->
  code =
    if @c_()
      if args && args.length > 0
        "#{@rn_(options)}#{method}(#{args})"
      else
        "#{@rn_(options)}#{method}"
    else
      null
  [code, @ORDER_FUNCTION_CALL]

Blockly.Ruby.characterSetVariable_ = (name, val, operator = '=') ->
  if @c_()
    "#{@rn_({ dropSelf: false })}#{name} #{operator} #{val}\n"
  else
    ''

Blockly.Ruby.characterEvent_ = (block, bodyName, name, arg = null) ->
  if c = @c_()
    @rs_().push(c)
    try
      body = Blockly.Ruby.statementToCode(block, bodyName) || '\n'
    finally
      @rs_().pop()

    if arg
      arg = ", #{arg}"
    else
      arg = ''

    """


    #{@rn_()}on(:#{name}#{arg}) do
    #{body}end

    """
  else
    ''

Blockly.Ruby.finish = (code) ->
  requires = []
  prepares = []
  definitions = []
  for name of Blockly.Ruby.definitions_
    do (name) ->
      def = Blockly.Ruby.definitions_[name]
      if _.isString(def)
        if name.match(/^require__/)
          requires.push(def)
        else if name.match(/^prepare__/)
          prepares.push(def)
        else
          definitions.push(def)

  if prepares.length == 0 && definitions.length == 0 && code.length == 0
    return ''

  allDefs = requires.join('\n') + '\n\n'

  if prepares.length > 0
    allDefs += prepares.join('\n') + '\n\n'

  if definitions.length > 0
    allDefs += definitions.join('\n')
      .replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n')

  allDefs + code

Blockly.Ruby.scrubNakedValue = (line) ->
  line + '\n'

Blockly.Ruby.escapeChars_ =
  '"': '\\"'

Blockly.Ruby.quote_ = (string) ->
  # copy and modified goog.string.quote:
  # http://docs.closure-library.googlecode.com/git/namespace_goog_string.html
  s = String(string)
  sb = ['"']
  for i in [0...s.length]
    do (i) ->
      ch = s.charAt(i)
      sb[i + 1] = Blockly.Ruby.escapeChars_[ch] || ch
  sb.push('"')
  sb.join('')

Blockly.Ruby.scrub_ = (block, code) ->
  if code == null
    return ''

  commentCode = ''
  if !block.outputConnection || !block.outputConnection.targetConnection
    comment = block.getCommentText()
    if comment
      commentCode += @prefixLines(comment, '# ') + '\n'

    for input in block.inputList
      do (input) =>
        if input.type == Blockly.INPUT_VALUE
          childBlock = input.connection.targetBlock()
          if childBlock
            comment = @allNestedComments(childBlock)
            if comment
              commentCode += @prefixLines(comment, '# ')

  nextBlock = block.nextConnection && block.nextConnection.targetBlock()
  nextCode = this.blockToCode(nextBlock)
  commentCode + code + nextCode

Blockly.Ruby.blockToCode_ = Blockly.Ruby.blockToCode
Blockly.Ruby.blockToCode = (block) ->
  if block && !block.disabled && block.type.match(/^hardware_/)
    @definitions_['prepare__init_hardware'] = 'init_hardware'
  @blockToCode_(block)