nudge 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/bin/nudge +3 -0
- data/lib/cli/runner.rb +41 -0
- data/lib/interpreter/interpreter.rb +4 -4
- data/lib/interpreter/nudge_program.rb +8 -0
- data/lib/nudge.rb +2 -0
- data/readme.md +9 -1
- data/spec/command_line/command_line_spec.rb +131 -0
- data/spec/interpreter/interpreter_spec.rb +8 -5
- data/spec/interpreter/nudge_program_class_methods_spec.rb +32 -0
- metadata +12 -6
data/Rakefile
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'rake'
|
2
2
|
|
3
|
+
|
4
|
+
|
3
5
|
begin
|
4
6
|
require 'jeweler'
|
5
7
|
Jeweler::Tasks.new do |gemspec|
|
@@ -20,10 +22,10 @@ begin
|
|
20
22
|
# files
|
21
23
|
gemspec.files.exclude '_spikes/**'
|
22
24
|
gemspec.files.exclude('exploring_nudge/**')
|
23
|
-
|
24
25
|
end
|
25
26
|
|
26
27
|
Jeweler::GemcutterTasks.new
|
27
28
|
rescue LoadError
|
28
29
|
puts "Jeweler not available. Install it with: gem install jeweler"
|
29
|
-
end
|
30
|
+
end
|
31
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/bin/nudge
ADDED
data/lib/cli/runner.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
module Nudge
|
4
|
+
class CliRunner
|
5
|
+
attr_accessor :filename
|
6
|
+
attr_accessor :raw_code
|
7
|
+
attr_accessor :nudge_program
|
8
|
+
attr_accessor :interpreter
|
9
|
+
attr_accessor :options
|
10
|
+
attr_accessor :result
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(filename, options={})
|
14
|
+
@filename = filename
|
15
|
+
@nudge_program = NudgeProgram.new("")
|
16
|
+
@options = options
|
17
|
+
@interpreter = Interpreter.new(@options)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def setup(options = {})
|
22
|
+
@raw_code = IO.open(@filename)
|
23
|
+
@interpreter.reset(@raw_code)
|
24
|
+
options[:variables].each {|name, val| @interpreter.bind_variable(name, val)} if options[:variables]
|
25
|
+
options[:sensors].each {|name, block| @interpreter.register_sensor(name, &block)} if options[:sensors]
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def run
|
30
|
+
return @interpreter.run
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
class CliParser
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -13,7 +13,7 @@ module Nudge
|
|
13
13
|
# * ... NilPoint, do nothing
|
14
14
|
|
15
15
|
class Interpreter
|
16
|
-
attr_accessor :program, :
|
16
|
+
attr_accessor :program, :step_limit, :steps
|
17
17
|
attr_accessor :stacks, :instructions_library, :variables, :names, :types
|
18
18
|
attr_accessor :last_name, :evaluate_references
|
19
19
|
attr_accessor :sensors
|
@@ -24,7 +24,7 @@ module Nudge
|
|
24
24
|
initialProgram = params[:program] || nil
|
25
25
|
@program = initialProgram
|
26
26
|
@types = params[:types] || NudgeType.all_types
|
27
|
-
@
|
27
|
+
@step_limit = params[:step_limit] || 3000
|
28
28
|
@sensors = Hash.new
|
29
29
|
|
30
30
|
instructions = params[:instructions] || Instruction.all_instructions
|
@@ -105,9 +105,9 @@ module Nudge
|
|
105
105
|
|
106
106
|
# Checks to see if either stopping condition applies:
|
107
107
|
# 1. Is the <b>:exec</b> stack empty?
|
108
|
-
# 2. Are the number of steps greater than self.
|
108
|
+
# 2. Are the number of steps greater than self.step_limit?
|
109
109
|
def notDone?
|
110
|
-
@stacks[:exec].depth > 0 && @steps < @
|
110
|
+
@stacks[:exec].depth > 0 && @steps < @step_limit
|
111
111
|
end
|
112
112
|
|
113
113
|
|
@@ -5,6 +5,12 @@ Treetop.load(File.join(File.dirname(__FILE__),'grammars', "nudge_codeblock.treet
|
|
5
5
|
|
6
6
|
module Nudge
|
7
7
|
class NudgeProgram
|
8
|
+
|
9
|
+
def self.random(options = {})
|
10
|
+
sourcecode = CodeType.any_value(options)
|
11
|
+
NudgeProgram.new(sourcecode)
|
12
|
+
end
|
13
|
+
|
8
14
|
|
9
15
|
attr_accessor :linked_code,:footnotes
|
10
16
|
attr_accessor :raw_code
|
@@ -22,6 +28,8 @@ module Nudge
|
|
22
28
|
|
23
29
|
|
24
30
|
|
31
|
+
|
32
|
+
|
25
33
|
def program_split!
|
26
34
|
split_at_first_guillemet=@raw_code.partition( /^(?=«)/ )
|
27
35
|
@code_section = split_at_first_guillemet[0].strip
|
data/lib/nudge.rb
CHANGED
data/readme.md
CHANGED
@@ -8,8 +8,16 @@ See the [project Wiki](http://github.com/Vaguery/Nudge/wikis) for a more thoroug
|
|
8
8
|
|
9
9
|
## Getting started
|
10
10
|
|
11
|
-
|
11
|
+
gem install nudge
|
12
12
|
|
13
|
+
As of this writing, the `nudge` gem can be used as a library in your Ruby programs. S Real Soon Now, it'll be part of a more interesting gem…
|
14
|
+
|
15
|
+
Meanwhile, try this:
|
16
|
+
|
17
|
+
require 'nudge'
|
18
|
+
include Nudge
|
19
|
+
|
20
|
+
my_program = Nudge.random(target_size_in_points:20) # generates
|
13
21
|
## Requirements
|
14
22
|
|
15
23
|
The interpreter code relies heavily on functional programming features of Ruby 1.9+. If you have not yet installed Ruby 1.9, I'd recommend using [rvm](http://rvm.beginrescueend.com/) to set up a special "sandbox" version of 1.9 until you're ready to upgrade your development or production machine.
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
3
|
+
include Nudge
|
4
|
+
|
5
|
+
|
6
|
+
describe "CliRunner" do
|
7
|
+
before(:each) do
|
8
|
+
IO.stub!(:open).and_return("xyz123") # to avoid hitting the file
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should capture the filename in an attribute" do
|
12
|
+
CliRunner.new("beeboop").filename.should == "beeboop"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should create an Interpreter instance" do
|
16
|
+
Interpreter.should_receive(:new)
|
17
|
+
CliRunner.new("beeboop")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should capture other options it gets" do
|
21
|
+
lambda{CliRunner.new("foo", types:["int"])}.should_not raise_error
|
22
|
+
a = CliRunner.new("bar", types:["bool"], step_limit: 10000)
|
23
|
+
a.options.should == {:types=>["bool"], :step_limit=>10000}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should pass those options down into its Interpreter instance's initialization" do
|
27
|
+
lambda{CliRunner.new("foo", types:["int"])}.should_not raise_error
|
28
|
+
a = CliRunner.new("bar", types:["bool"], step_limit: 10000)
|
29
|
+
a.interpreter.step_limit.should == 10000
|
30
|
+
a.interpreter.types.should == ["bool"]
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
describe "setup" do
|
35
|
+
before(:each) do
|
36
|
+
IO.stub!(:open).and_return("ref g") # to avoid hitting the file
|
37
|
+
@cr = CliRunner.new("beebop")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should open the file and read in the program" do
|
41
|
+
IO.should_receive(:open).with("beebop").and_return("block {}")
|
42
|
+
CliRunner.new("beebop").setup
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should save the read filestream into #raw_code" do
|
46
|
+
@cr.setup
|
47
|
+
@cr.raw_code.should == "ref g"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should reset the Interpreter with the new program" do
|
51
|
+
@cr.setup
|
52
|
+
@cr.interpreter.program.should == @cr.raw_code
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should be able to accept an optional Hash of variable bindings" do
|
56
|
+
lambda{@cr.setup(variables:{"x" => ValuePoint.new("int", 9)})}.should_not raise_error
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should build those bindings into its interpreter" do
|
60
|
+
@cr.setup(variables:{"x" => ValuePoint.new("int",1002)})
|
61
|
+
@cr.interpreter.variables["x"].value.should == 1002
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be able to accept an optional Hash of sensor definitions" do
|
65
|
+
lambda{@cr.setup(sensors:{"x" => Proc.new {|me| "hi there"}} )}.should_not raise_error
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should register those sensors in the interpreter" do
|
69
|
+
@cr.setup(sensors:{"x" => Proc.new {|me| "hi there"}})
|
70
|
+
@cr.interpreter.sensors["x"].call.should == "hi there"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
describe "run" do
|
76
|
+
before(:each) do
|
77
|
+
IO.stub!(:open).and_return("value «bool»\n«bool» false") # to avoid hitting the file
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should run the interpreter" do
|
81
|
+
cr = CliRunner.new("fakefile")
|
82
|
+
cr.setup
|
83
|
+
cr.interpreter.should_receive(:run)
|
84
|
+
cr.run
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should pass along the return value of the interpreter (the sensors' output)" do
|
88
|
+
cr = CliRunner.new("fakefile")
|
89
|
+
cr.setup
|
90
|
+
cr.interpreter.register_sensor("output") {|intrprtr| 82}
|
91
|
+
cr.run.should == {"output"=>82}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
describe CliParser do
|
98
|
+
describe "filename" do
|
99
|
+
it "should read the filename from ARGV"
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "step_limit" do
|
103
|
+
it "should be an optional parameter"
|
104
|
+
|
105
|
+
it "should parse the step_limit from ARGV"
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "types" do
|
109
|
+
it "should be an optional parameter"
|
110
|
+
|
111
|
+
it "should parse the type_names from ARGV"
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "instructions" do
|
115
|
+
it "should be an optional parameter"
|
116
|
+
|
117
|
+
it "should parse the instruction_names from ARGV"
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "variable bindings" do
|
121
|
+
it "should be an optional parameter"
|
122
|
+
|
123
|
+
it "should parse the variable bindings from ARGV"
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "sensors" do
|
127
|
+
it "should be an optional parameter"
|
128
|
+
|
129
|
+
it "should parse the sensor definitions from ARGV"
|
130
|
+
end
|
131
|
+
end
|
@@ -405,9 +405,9 @@ describe "stepping" do
|
|
405
405
|
lambda{3.times {@ii.step}}.should_not raise_error
|
406
406
|
end
|
407
407
|
|
408
|
-
it "should step only until the
|
408
|
+
it "should step only until the step_limit has not been reached, if the :exec stack is full" do
|
409
409
|
myCode = "block {"*20 + "}"*20
|
410
|
-
@ii.
|
410
|
+
@ii.step_limit = 3
|
411
411
|
@ii.reset(myCode)
|
412
412
|
lambda{15.times {@ii.step}}.should_not raise_error
|
413
413
|
end
|
@@ -431,8 +431,8 @@ describe "running" do
|
|
431
431
|
@ii.reset(myCode)
|
432
432
|
end
|
433
433
|
|
434
|
-
it "should run until the
|
435
|
-
@ii.
|
434
|
+
it "should run until the step_limit has been reached, if the :exec stack isn't empty" do
|
435
|
+
@ii.step_limit = 9
|
436
436
|
@ii.run
|
437
437
|
@ii.steps.should == 9
|
438
438
|
end
|
@@ -449,10 +449,13 @@ describe "running" do
|
|
449
449
|
@ii.steps.should == 0
|
450
450
|
end
|
451
451
|
|
452
|
-
it "should #fire_all_sensors at the end of running" do
|
452
|
+
it "should #fire_all_sensors at the end of running if any are defined" do
|
453
|
+
@ii.register_sensor("y")
|
453
454
|
@ii.should_receive(:fire_all_sensors)
|
454
455
|
@ii.run
|
455
456
|
end
|
457
|
+
|
458
|
+
it "should return Stack#inspect for all its stacks if no sensors are defined"
|
456
459
|
end
|
457
460
|
|
458
461
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), "/../spec_helper")
|
3
|
+
include Nudge
|
4
|
+
|
5
|
+
|
6
|
+
describe NudgeProgram do
|
7
|
+
describe "#random" do
|
8
|
+
it "should return a new random-code program, given no params" do
|
9
|
+
lambda{NudgeProgram.random}.should_not raise_error
|
10
|
+
NudgeProgram.random.should be_a_kind_of(NudgeProgram)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should use the 'global' defaults as needed" do
|
14
|
+
NudgeProgram.random.points.should == 20
|
15
|
+
Instruction.should_receive(:all_instructions).at_least(1).times.and_return([IntAddInstruction])
|
16
|
+
NudgeType.should_receive(:all_types).at_least(1).times.and_return([IntType])
|
17
|
+
NudgeProgram.random
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should accept an overridden_parameters Hash" do
|
21
|
+
NudgeProgram.random(target_size_in_points:30).points.should == 30
|
22
|
+
NudgeProgram.random(probabilities: {b:10, r:0, v:0, i:0}).blueprint.
|
23
|
+
scan("block").length.should == 20 # there should be 20 occurrences of 'block' only!
|
24
|
+
NudgeProgram.random(reference_names:["x"], probabilities: {b:0, r:10, v:0, i:0}).blueprint.
|
25
|
+
scan("ref x").length.should == 19 # there should be 19 occurrences of 'ref x' in a wrapper
|
26
|
+
NudgeProgram.random(type_names:["foo"], probabilities: {b:0, r:0, v:10, i:0}).blueprint.
|
27
|
+
scan("foo").length.should == 38 # there should be 19 occurrences of 'value «foo»', plus fn's
|
28
|
+
NudgeProgram.random(instruction_names:["bool_xor"], probabilities: {b:0, r:0, v:0, i:10}).blueprint.
|
29
|
+
scan("bool_xor").length.should == 19 # there should be 19 occurrences of 'do bool_xor'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bill Tozier
|
@@ -16,8 +16,8 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-03-
|
20
|
-
default_executable:
|
19
|
+
date: 2010-03-28 00:00:00 -04:00
|
20
|
+
default_executable: nudge
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
23
|
name: treetop
|
@@ -49,8 +49,8 @@ dependencies:
|
|
49
49
|
version_requirements: *id002
|
50
50
|
description: Provides a Ruby library & CLI implementing a flexible Nudge Language interpreter, plus a set of generators for adding domain-specific instructions and types.
|
51
51
|
email: bill@vagueinnovation.com
|
52
|
-
executables:
|
53
|
-
|
52
|
+
executables:
|
53
|
+
- nudge
|
54
54
|
extensions: []
|
55
55
|
|
56
56
|
extra_rdoc_files:
|
@@ -60,6 +60,8 @@ files:
|
|
60
60
|
- LICENSE.txt
|
61
61
|
- Rakefile
|
62
62
|
- VERSION
|
63
|
+
- bin/nudge
|
64
|
+
- lib/cli/runner.rb
|
63
65
|
- lib/instructions/bool/bool_and.rb
|
64
66
|
- lib/instructions/bool/bool_define.rb
|
65
67
|
- lib/instructions/bool/bool_depth.rb
|
@@ -232,6 +234,7 @@ files:
|
|
232
234
|
- lib/interpreter/types/pushTypes.rb
|
233
235
|
- lib/nudge.rb
|
234
236
|
- readme.md
|
237
|
+
- spec/command_line/command_line_spec.rb
|
235
238
|
- spec/fixtures/just_block.example
|
236
239
|
- spec/fixtures/just_block_with_newline.example
|
237
240
|
- spec/fixtures/long_arithmetic.example
|
@@ -369,6 +372,7 @@ files:
|
|
369
372
|
- spec/interpreter/instruction_spec.rb
|
370
373
|
- spec/interpreter/interpreter_spec.rb
|
371
374
|
- spec/interpreter/nil_point_spec.rb
|
375
|
+
- spec/interpreter/nudge_program_class_methods_spec.rb
|
372
376
|
- spec/interpreter/nudge_program_spec.rb
|
373
377
|
- spec/interpreter/reference_point_spec.rb
|
374
378
|
- spec/interpreter/stack_spec.rb
|
@@ -411,6 +415,7 @@ signing_key:
|
|
411
415
|
specification_version: 3
|
412
416
|
summary: Nudge Language interpreter
|
413
417
|
test_files:
|
418
|
+
- spec/command_line/command_line_spec.rb
|
414
419
|
- spec/instructions/bool/bool_and_spec.rb
|
415
420
|
- spec/instructions/bool/bool_define_spec.rb
|
416
421
|
- spec/instructions/bool/bool_depth_spec.rb
|
@@ -542,6 +547,7 @@ test_files:
|
|
542
547
|
- spec/interpreter/instruction_spec.rb
|
543
548
|
- spec/interpreter/interpreter_spec.rb
|
544
549
|
- spec/interpreter/nil_point_spec.rb
|
550
|
+
- spec/interpreter/nudge_program_class_methods_spec.rb
|
545
551
|
- spec/interpreter/nudge_program_spec.rb
|
546
552
|
- spec/interpreter/reference_point_spec.rb
|
547
553
|
- spec/interpreter/stack_spec.rb
|