blockly_interpreter 0.2.0

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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +12 -0
  5. data/COPYING +8 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +91 -0
  8. data/Guardfile +22 -0
  9. data/README.md +72 -0
  10. data/Rakefile +10 -0
  11. data/app/assets/javascripts/blockly_interpreter/extension_blocks.js +1 -0
  12. data/app/assets/javascripts/blockly_interpreter/extension_blocks/dates.js +16 -0
  13. data/app/assets/javascripts/blockly_interpreter/extension_blocks/debugging.js +17 -0
  14. data/app/assets/javascripts/blockly_interpreter/extension_blocks/lists.js +45 -0
  15. data/app/assets/javascripts/blockly_interpreter/extension_blocks/logic.js +274 -0
  16. data/app/assets/javascripts/blockly_interpreter/extension_blocks/text.js.erb +21 -0
  17. data/bin/_guard-core +16 -0
  18. data/bin/console +14 -0
  19. data/bin/guard +16 -0
  20. data/bin/rake +16 -0
  21. data/bin/setup +7 -0
  22. data/blockly_interpreter.gemspec +33 -0
  23. data/exe/blocklyi +13 -0
  24. data/exe/rublocklyc +31 -0
  25. data/lib/blockly_interpreter.rb +25 -0
  26. data/lib/blockly_interpreter/block.rb +113 -0
  27. data/lib/blockly_interpreter/block_library.rb +14 -0
  28. data/lib/blockly_interpreter/console_interpreter.rb +15 -0
  29. data/lib/blockly_interpreter/core_blocks.rb +55 -0
  30. data/lib/blockly_interpreter/core_blocks/arithmetic_operator_block.rb +24 -0
  31. data/lib/blockly_interpreter/core_blocks/boolean_block.rb +23 -0
  32. data/lib/blockly_interpreter/core_blocks/comparison_operator_block.rb +50 -0
  33. data/lib/blockly_interpreter/core_blocks/for_block.rb +68 -0
  34. data/lib/blockly_interpreter/core_blocks/for_each_block.rb +42 -0
  35. data/lib/blockly_interpreter/core_blocks/get_variable_block.rb +19 -0
  36. data/lib/blockly_interpreter/core_blocks/if_block.rb +105 -0
  37. data/lib/blockly_interpreter/core_blocks/lists_create_empty_block.rb +17 -0
  38. data/lib/blockly_interpreter/core_blocks/lists_create_with_block.rb +48 -0
  39. data/lib/blockly_interpreter/core_blocks/lists_get_index_block.rb +95 -0
  40. data/lib/blockly_interpreter/core_blocks/logic_negate_block.rb +20 -0
  41. data/lib/blockly_interpreter/core_blocks/logical_operator_block.rb +22 -0
  42. data/lib/blockly_interpreter/core_blocks/number_block.rb +23 -0
  43. data/lib/blockly_interpreter/core_blocks/procedure_block.rb +49 -0
  44. data/lib/blockly_interpreter/core_blocks/procedures_call_no_return_block.rb +21 -0
  45. data/lib/blockly_interpreter/core_blocks/procedures_call_return_block.rb +21 -0
  46. data/lib/blockly_interpreter/core_blocks/procedures_def_no_return_block.rb +31 -0
  47. data/lib/blockly_interpreter/core_blocks/procedures_def_return_block.rb +64 -0
  48. data/lib/blockly_interpreter/core_blocks/procedures_if_return_block.rb +45 -0
  49. data/lib/blockly_interpreter/core_blocks/repeat_times_block.rb +33 -0
  50. data/lib/blockly_interpreter/core_blocks/set_variable_block.rb +24 -0
  51. data/lib/blockly_interpreter/core_blocks/text_block.rb +23 -0
  52. data/lib/blockly_interpreter/core_blocks/text_change_case_block.rb +32 -0
  53. data/lib/blockly_interpreter/core_blocks/text_join_block.rb +50 -0
  54. data/lib/blockly_interpreter/dsl.rb +291 -0
  55. data/lib/blockly_interpreter/dsl_generator.rb +147 -0
  56. data/lib/blockly_interpreter/engine.rb +8 -0
  57. data/lib/blockly_interpreter/execution_context.rb +72 -0
  58. data/lib/blockly_interpreter/extension_blocks.rb +25 -0
  59. data/lib/blockly_interpreter/extension_blocks/date_today_block.rb +17 -0
  60. data/lib/blockly_interpreter/extension_blocks/debug_message_block.rb +18 -0
  61. data/lib/blockly_interpreter/extension_blocks/lists_append_block.rb +34 -0
  62. data/lib/blockly_interpreter/extension_blocks/lists_concat_block.rb +37 -0
  63. data/lib/blockly_interpreter/extension_blocks/lists_include_operator_block.rb +52 -0
  64. data/lib/blockly_interpreter/extension_blocks/object_present_block.rb +21 -0
  65. data/lib/blockly_interpreter/extension_blocks/switch_block.rb +107 -0
  66. data/lib/blockly_interpreter/extension_blocks/text_inflect_block.rb +27 -0
  67. data/lib/blockly_interpreter/generic_block_dsl_generator.rb +64 -0
  68. data/lib/blockly_interpreter/interpreter.rb +25 -0
  69. data/lib/blockly_interpreter/parser.rb +117 -0
  70. data/lib/blockly_interpreter/program.rb +51 -0
  71. data/lib/blockly_interpreter/program_cache.rb +19 -0
  72. data/lib/blockly_interpreter/test_helper.rb +98 -0
  73. data/lib/blockly_interpreter/version.rb +3 -0
  74. metadata +272 -0
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ goog.provide('BlocklyInterpreter.ExtensionBlocks.text');
4
+ goog.require('Blockly.Blocks');
5
+
6
+ Blockly.Blocks['text_inflect'] = {
7
+ init: function() {
8
+ var inflections = <%= BlocklyInterpreter::ExtensionBlocks::TextInflectBlock::INFLECTIONS.to_json %>;
9
+ var dropdownOptions = _.map(inflections, function (inflection) {
10
+ return [inflection, inflection]
11
+ });
12
+
13
+ this.appendValueInput('TEXT')
14
+ .appendField(new Blockly.FieldDropdown(dropdownOptions), 'OP')
15
+ .appendField('text')
16
+ .setCheck('String');
17
+
18
+ this.setOutput(true, 'String');
19
+ this.setColour(Blockly.Blocks.texts.HUE);
20
+ }
21
+ }
data/bin/_guard-core ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application '_guard-core' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', '_guard-core')
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blockly_interpreter"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/guard ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'guard' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', 'guard')
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'blockly_interpreter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "blockly_interpreter"
8
+ spec.version = BlocklyInterpreter::VERSION
9
+ spec.authors = ["Nat Budin"]
10
+ spec.email = ["natbudin@gmail.com"]
11
+
12
+ spec.summary = %q{An interpreter for Blockly programs}
13
+ spec.description = %q{Blockly is a library from Google for building visual programming editors. This gem is an interpreter for Blockly programs in Ruby.}
14
+ spec.homepage = "https://github.com/patientslikeme/blockly_interpreter"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "nokogiri"
22
+ spec.add_dependency "activesupport"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest"
27
+ spec.add_development_dependency "minitest-reporters"
28
+ spec.add_development_dependency "timecop"
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "guard"
31
+ spec.add_development_dependency "guard-minitest"
32
+ spec.add_development_dependency "terminal-notifier-guard"
33
+ end
data/exe/blocklyi ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blockly_interpreter"
5
+
6
+ program_name = ARGV[0]
7
+ unless program_name
8
+ puts "Please specify a program name to run."
9
+ exit!
10
+ end
11
+
12
+ xml = File.open(program_name).read
13
+ BlocklyInterpreter::ConsoleInterpreter.new(xml).execute
data/exe/rublocklyc ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blockly_interpreter"
5
+
6
+ program_name = ARGV[0]
7
+ unless program_name
8
+ puts "Please specify a program name to compile."
9
+ exit!
10
+ end
11
+
12
+ module ConsoleDSL
13
+ def console_print(content = nil, &proc)
14
+ block :console_print do
15
+ value :VALUE do
16
+ if block_given?
17
+ instance_exec &proc
18
+ else
19
+ text content
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ BlocklyInterpreter::DSL::BlockContext.send :include, ConsoleDSL
26
+
27
+ xml = BlocklyInterpreter::DSL.build_xml do
28
+ binding.eval(File.open(program_name).read, program_name)
29
+ end
30
+
31
+ STDOUT.write xml
@@ -0,0 +1,25 @@
1
+ require "blockly_interpreter/version"
2
+ require "active_support/dependencies/autoload"
3
+ require "active_support/core_ext"
4
+
5
+ if defined?(::Rails::Engine)
6
+ # Rails autoloading will take care of the requires for us, and explicitly doing it will
7
+ # break it.
8
+ require 'blockly_interpreter/engine'
9
+ else
10
+ module BlocklyInterpreter
11
+ extend ActiveSupport::Autoload
12
+
13
+ autoload :Block
14
+ autoload :BlockLibrary
15
+ autoload :CoreBlocks
16
+ autoload :DSL
17
+ autoload :DSLGenerator
18
+ autoload :ExecutionContext
19
+ autoload :GenericBlockDSLGenerator
20
+ autoload :Interpreter
21
+ autoload :Parser
22
+ autoload :ProgramCache
23
+ autoload :Program
24
+ end
25
+ end
@@ -0,0 +1,113 @@
1
+ require 'nokogiri'
2
+
3
+ class BlocklyInterpreter::Block
4
+ class << self
5
+ attr_accessor :block_type
6
+ end
7
+
8
+ attr_reader :block_type, :values, :statements, :fields, :next_block, :mutation, :comment, :comment_pinned, :is_shadow, :x, :y
9
+ alias_method :is_shadow?, :is_shadow
10
+
11
+ def initialize(block_type, fields, values, statements, next_block, mutation, comment, comment_pinned, is_shadow, x, y)
12
+ @block_type = block_type
13
+ @fields = fields
14
+ @values = values
15
+ @statements = statements
16
+ @next_block = next_block
17
+ @mutation = mutation
18
+ @comment = comment
19
+ @comment_pinned = comment_pinned
20
+ @is_shadow = is_shadow
21
+ @x = x
22
+ @y = y
23
+ end
24
+
25
+ def execute_statement(execution_context)
26
+ end
27
+
28
+ def value(execution_context)
29
+ nil
30
+ end
31
+
32
+ def each_block(iterate_subblocks = true)
33
+ return to_enum(:each_block, iterate_subblocks) unless block_given?
34
+
35
+ yield self
36
+
37
+ if iterate_subblocks
38
+ statements.each do |key, statement|
39
+ statement.each_block(iterate_subblocks) do |block|
40
+ yield block
41
+ end
42
+ end
43
+ end
44
+
45
+ if next_block
46
+ next_block.each_block(iterate_subblocks) do |block|
47
+ yield block
48
+ end
49
+ end
50
+ end
51
+
52
+ def to_dsl
53
+ BlocklyInterpreter::GenericBlockDSLGenerator.new(self).dsl
54
+ end
55
+
56
+ def has_comment?
57
+ comment.present?
58
+ end
59
+
60
+ def has_position?
61
+ x || y
62
+ end
63
+
64
+ def to_xml_element(document)
65
+ tag_name = is_shadow ? 'shadow' : 'block'
66
+
67
+ Nokogiri::XML::Element.new(tag_name, document).tap do |node|
68
+ node['type'] = block_type
69
+ node['x'] = x if x
70
+ node['y'] = y if y
71
+ node.add_child(mutation.dup) if mutation
72
+
73
+ if comment
74
+ comment_node = Nokogiri::XML::Element.new('comment', document)
75
+ comment_node['pinned'] = 'true' if comment_pinned
76
+ node.add_child comment_node
77
+ end
78
+
79
+ fields.each do |name, value|
80
+ field_node = Nokogiri::XML::Element.new('field', document)
81
+ field_node['name'] = name
82
+ field_node.add_child Nokogiri::XML::Text.new(value, document)
83
+ node.add_child field_node
84
+ end
85
+
86
+ values.each do |name, value|
87
+ value_node = Nokogiri::XML::Element.new('value', document)
88
+ value_node['name'] = name
89
+ value_node.add_child value.to_xml_element(document)
90
+ node.add_child value_node
91
+ end
92
+
93
+ statements.each do |name, value|
94
+ statement_node = Nokogiri::XML::Element.new('statement', document)
95
+ statement_node['name'] = name
96
+ statement_node.add_child value.to_xml_element(document)
97
+ node.add_child statement_node
98
+ end
99
+
100
+ if next_block
101
+ next_block_node = Nokogiri::XML::Element.new('next_block', document)
102
+ next_block_node.add_child next_block.to_xml_element(document)
103
+ node.add_child next_block_node
104
+ end
105
+ end
106
+ end
107
+
108
+ def to_xml(options = {})
109
+ doc = Nokogiri::XML::Document.new
110
+ element = to_xml_element(doc)
111
+ element.to_xml(options = {})
112
+ end
113
+ end
@@ -0,0 +1,14 @@
1
+ module BlocklyInterpreter::BlockLibrary
2
+ attr_accessor :block_classes
3
+
4
+ def block_classes
5
+ @block_classes ||= []
6
+ end
7
+
8
+ def register!(parser_class = BlocklyInterpreter::Parser, block_context_class = BlocklyInterpreter::DSL::BlockContext)
9
+ block_classes.each do |block_class|
10
+ parser_class.register_block_class block_class
11
+ block_context_class.register_block_class block_class
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class BlocklyInterpreter::ConsoleInterpreter < BlocklyInterpreter::Interpreter
2
+ class ConsolePrintBlock < BlocklyInterpreter::Block
3
+ def execute_statement(execution_context)
4
+ puts values['VALUE'].value(execution_context)
5
+ end
6
+ end
7
+
8
+ def block_class_for_element(element)
9
+ case element['type']
10
+ when 'console_print' then ConsolePrintBlock
11
+ else
12
+ super(element)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ module BlocklyInterpreter::CoreBlocks
2
+ extend ActiveSupport::Autoload
3
+ extend BlocklyInterpreter::BlockLibrary
4
+
5
+ autoload :ArithmeticOperatorBlock
6
+ autoload :BooleanBlock
7
+ autoload :ComparisonOperatorBlock
8
+ autoload :ForBlock
9
+ autoload :ForEachBlock
10
+ autoload :GetVariableBlock
11
+ autoload :IfBlock
12
+ autoload :ListsCreateEmptyBlock
13
+ autoload :ListsCreateWithBlock
14
+ autoload :ListsGetIndexBlock
15
+ autoload :LogicNegateBlock
16
+ autoload :LogicalOperatorBlock
17
+ autoload :NumberBlock
18
+ autoload :ProcedureBlock
19
+ autoload :ProceduresCallNoReturnBlock
20
+ autoload :ProceduresCallReturnBlock
21
+ autoload :ProceduresDefNoReturnBlock
22
+ autoload :ProceduresDefReturnBlock
23
+ autoload :ProceduresIfReturnBlock
24
+ autoload :RepeatTimesBlock
25
+ autoload :SetVariableBlock
26
+ autoload :TextBlock
27
+ autoload :TextChangeCaseBlock
28
+ autoload :TextJoinBlock
29
+
30
+ self.block_classes = [
31
+ ArithmeticOperatorBlock,
32
+ BooleanBlock,
33
+ ComparisonOperatorBlock,
34
+ ForBlock,
35
+ ForEachBlock,
36
+ GetVariableBlock,
37
+ IfBlock,
38
+ ListsCreateEmptyBlock,
39
+ ListsCreateWithBlock,
40
+ ListsGetIndexBlock,
41
+ LogicNegateBlock,
42
+ LogicalOperatorBlock,
43
+ NumberBlock,
44
+ ProceduresCallNoReturnBlock,
45
+ ProceduresCallReturnBlock,
46
+ ProceduresDefNoReturnBlock,
47
+ ProceduresDefReturnBlock,
48
+ ProceduresIfReturnBlock,
49
+ RepeatTimesBlock,
50
+ SetVariableBlock,
51
+ TextBlock,
52
+ TextChangeCaseBlock,
53
+ TextJoinBlock
54
+ ]
55
+ end
@@ -0,0 +1,24 @@
1
+ class BlocklyInterpreter::CoreBlocks::ArithmeticOperatorBlock < BlocklyInterpreter::Block
2
+ self.block_type = :math_arithmetic
3
+
4
+ def value(execution_context)
5
+ a = values['A'].value(execution_context)
6
+ b = values['B'].value(execution_context)
7
+
8
+ case fields['OP'].to_s.upcase
9
+ when 'ADD' then a + b
10
+ when 'MINUS' then a - b
11
+ when 'MULTIPLY' then a * b
12
+ when 'DIVIDE' then a / b
13
+ when 'POWER' then a ** b
14
+ end
15
+ end
16
+
17
+ module DSLMethods
18
+ def math_arithmetic(op, a = nil, b = nil, &proc)
19
+ @blocks << BlocklyInterpreter::DSL::BinaryOperationBlockBuilder.new("math_arithmetic", op, a, b).tap do |builder|
20
+ builder.instance_exec(&proc) if block_given?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ class BlocklyInterpreter::CoreBlocks::BooleanBlock < BlocklyInterpreter::Block
2
+ self.block_type = :logic_boolean
3
+
4
+ def to_bool
5
+ fields['BOOL'] == 'TRUE'
6
+ end
7
+
8
+ def value(execution_context)
9
+ to_bool
10
+ end
11
+
12
+ def to_dsl
13
+ "logic_boolean #{to_bool.inspect}"
14
+ end
15
+
16
+ module DSLMethods
17
+ def logic_boolean(value)
18
+ block :logic_boolean do
19
+ field :BOOL, value ? "TRUE" : "FALSE"
20
+ end
21
+ end
22
+ end
23
+ end