nudge 0.1.0 → 0.1.1

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -16,6 +16,7 @@ module Nudge
16
16
  attr_accessor :program, :stepLimit, :steps
17
17
  attr_accessor :stacks, :instructions_library, :variables, :names, :types
18
18
  attr_accessor :last_name, :evaluate_references
19
+ attr_accessor :sensors
19
20
 
20
21
 
21
22
  # A program to be interpreted can be passed in as an optional parameter
@@ -24,6 +25,7 @@ module Nudge
24
25
  @program = initialProgram
25
26
  @types = params[:types] || NudgeType.all_types
26
27
  @stepLimit = params[:step_limit] || 3000
28
+ @sensors = Hash.new
27
29
 
28
30
  instructions = params[:instructions] || Instruction.all_instructions
29
31
  @instructions_library = Hash.new {|hash, key| raise InstructionPoint::InstructionNotFoundError,
@@ -54,6 +56,7 @@ module Nudge
54
56
  @program = program
55
57
  self.clear_stacks
56
58
  self.reset_names
59
+ self.reset_sensors
57
60
  if program
58
61
  @stacks[:exec].push(NudgeProgram.new(program).linked_code)
59
62
  end
@@ -67,6 +70,11 @@ module Nudge
67
70
  end
68
71
 
69
72
 
73
+ def depth(stackname)
74
+ @stacks[stackname].depth
75
+ end
76
+
77
+
70
78
  def peek(stackname)
71
79
  @stacks[stackname].peek
72
80
  end
@@ -127,6 +135,7 @@ module Nudge
127
135
  while notDone?
128
136
  self.step
129
137
  end
138
+ fire_all_sensors
130
139
  end
131
140
 
132
141
 
@@ -226,5 +235,24 @@ module Nudge
226
235
  def disable_all_types
227
236
  @types = []
228
237
  end
238
+
239
+
240
+ def register_sensor(name, &block)
241
+ raise(ArgumentError, "Sensor name #{name} is not a string") unless name.kind_of?(String)
242
+ @sensors[name] = block
243
+ end
244
+
245
+
246
+ def reset_sensors
247
+ @sensors = Hash.new
248
+ end
249
+
250
+
251
+ def fire_all_sensors
252
+ @sensors.inject({}) do |result, (key, value)|
253
+ result[key] = @sensors[key].call(self)
254
+ result
255
+ end
256
+ end
229
257
  end
230
258
  end
@@ -9,7 +9,6 @@ module Nudge
9
9
  attr_accessor :linked_code,:footnotes
10
10
  attr_accessor :raw_code
11
11
  attr_accessor :code_section, :footnote_section
12
- attr_reader :parser
13
12
  attr_reader :points
14
13
 
15
14
 
@@ -17,7 +16,6 @@ module Nudge
17
16
  raise(ArgumentError, "NudgeProgram.new should be passed a string") unless sourcecode.kind_of?(String)
18
17
  @raw_code = sourcecode
19
18
  program_split!
20
- @parser = NudgeCodeblockParser.new
21
19
  relink_code!
22
20
  @points = self.points
23
21
  end
@@ -49,7 +47,7 @@ module Nudge
49
47
 
50
48
  def relink_code!
51
49
  if parses?
52
- @linked_code = @parser.parse(@code_section).to_point
50
+ @linked_code = NudgeCodeblockParser.new.parse(@code_section).to_point
53
51
  depth_first_association!
54
52
  else
55
53
  @linked_code = NilPoint.new
@@ -76,7 +74,7 @@ module Nudge
76
74
  def pursue_more_footnotes(codepoint_as_string, collected_footnotes = "")
77
75
  local_footnotes = ""
78
76
  if self.contains_valuepoints?(codepoint_as_string)
79
- local_parsetree = @parser.parse(codepoint_as_string)
77
+ local_parsetree = NudgeCodeblockParser.new.parse(codepoint_as_string)
80
78
  if local_parsetree != nil
81
79
  local_subtree = local_parsetree.to_point
82
80
  if local_subtree.kind_of?(CodeblockPoint)
@@ -213,7 +211,7 @@ module Nudge
213
211
 
214
212
 
215
213
  def parses?(program_blueprint = @code_section)
216
- (@parser.parse(program_blueprint) != nil)
214
+ (NudgeCodeblockParser.new.parse(program_blueprint) != nil)
217
215
  end
218
216
 
219
217
 
@@ -1,3 +1,4 @@
1
+ #encoding: utf-8
1
2
  module Nudge
2
3
 
3
4
  # Nudge Stacks are Arrays with some added convenience functions.
@@ -34,6 +35,13 @@ module Nudge
34
35
  @entries.length
35
36
  end
36
37
 
38
+ def inspect
39
+ result = @entries.reverse.inject("[") do |return_string, item|
40
+ return_string << "\n«#{item.type}» #{item.value},"
41
+ end
42
+ result.chop+"]"
43
+ end
44
+
37
45
  end
38
46
 
39
47
  end
@@ -45,6 +45,13 @@ describe "initialization" do
45
45
  @ii.steps.should == 0
46
46
  end
47
47
 
48
+ it "#reset should reset the #sensors Hash" do
49
+ @ii.register_sensor("z") {1201}
50
+ @ii.reset
51
+ @ii.sensors["z"].should == nil
52
+ end
53
+
54
+
48
55
  it "should load a complex CodeBlock as a single item on the exec stack" do
49
56
  myCode = "block {\ndo foo\n do bar\n block {\ndo baz}}"
50
57
  @ii.reset(myCode)
@@ -230,6 +237,31 @@ describe "Interpreter#peek" do
230
237
  end
231
238
 
232
239
 
240
+ describe "Interpreter#depth" do
241
+ before(:each) do
242
+ @ii = Interpreter.new()
243
+ @ii.clear_stacks
244
+ end
245
+
246
+ it "should invoke a particular stack's #depth method" do
247
+ 30.times { @ii.stacks[:donut].push(ValuePoint.new("donut", "0")) }
248
+ lambda{@ii.depth(:donut)}.should_not raise_error
249
+ @ii.depth(:donut).should == 30
250
+ end
251
+
252
+ it "should return 0 if the stack doesn't exist" do
253
+ lambda{@ii.depth(:nonexistent)}.should_not raise_error
254
+ @ii.depth(:nonexistent).should == 0
255
+ end
256
+
257
+ it "should validate the stackname as a symbol" do
258
+ lambda{@ii.depth("not there")}.should raise_error(ArgumentError)
259
+ lambda{@ii.depth(99)}.should raise_error(ArgumentError)
260
+ end
261
+ end
262
+
263
+
264
+
233
265
 
234
266
  describe "Interpreter#peek_value" do
235
267
  before(:each) do
@@ -417,6 +449,10 @@ describe "running" do
417
449
  @ii.steps.should == 0
418
450
  end
419
451
 
452
+ it "should #fire_all_sensors at the end of running" do
453
+ @ii.should_receive(:fire_all_sensors)
454
+ @ii.run
455
+ end
420
456
  end
421
457
 
422
458
 
@@ -458,3 +494,69 @@ describe "resetting" do
458
494
  ii.variables.keys.should == ["a"]
459
495
  end
460
496
  end
497
+
498
+
499
+ describe "sensors" do
500
+ before(:each) do
501
+ @ii = Interpreter.new
502
+ end
503
+
504
+ describe "register_sensor" do
505
+ it "should add a sensor block to the #sensors Hash" do
506
+ lambda{@ii.register_sensor("y") {}}.should_not raise_error
507
+ @ii.sensors.length.should == 1
508
+ @ii.sensors["y"].should be_a_kind_of(Proc)
509
+ end
510
+
511
+ it "should take a string name, validated as such" do
512
+ lambda{@ii.register_sensor("z")}.should_not raise_error
513
+ lambda{@ii.register_sensor(8)}.should raise_error(ArgumentError)
514
+ end
515
+
516
+ it "should take a block, which is called when the sensor is fired" do
517
+ @ii.register_sensor("y") {|x| 9}
518
+ @ii.sensors["y"].call.should == 9
519
+ end
520
+
521
+ it "should have access to the Interpreter state through a parameter" do
522
+ @ii.push(:int, 10202)
523
+ @ii.register_sensor("x1") {|interpreter| interpreter.peek_value(:int)}
524
+ @ii.sensors["x1"].call(@ii).should == 10202
525
+ end
526
+ end
527
+
528
+ describe "clear_sensors" do
529
+ it "should reset the #sensors Hash to empty" do
530
+ @ii.register_sensor("y1") {|x| 1}
531
+ @ii.register_sensor("y2") {|x| 2}
532
+ @ii.register_sensor("y3") {|x| 4}
533
+ @ii.sensors.keys.should == ["y1", "y2", "y3"]
534
+ @ii.reset_sensors
535
+ @ii.sensors.should == {}
536
+ end
537
+ end
538
+
539
+ describe "Interpreter#fire_all_sensors(name)" do
540
+ it "should call all registered sensors and return a Hash of results" do
541
+ @ii.register_sensor("y1") {|x| 1}
542
+ @ii.register_sensor("y2") {|x| 2}
543
+ @ii.register_sensor("y3") {|x| 4}
544
+ @ii.fire_all_sensors.should == {"y1"=>1, "y2"=>2, "y3"=>4}
545
+ end
546
+
547
+ it "should return an empty Hash if nothing is registered" do
548
+ @ii.fire_all_sensors.should == {}
549
+ end
550
+ end
551
+
552
+ describe "interrogating Interpreter state" do
553
+ it "should be possible to read anything about the Interpreter state" do
554
+ @ii.reset("block {value «int» value «int»}\n«int» 88\n«int» 11")
555
+ @ii.register_sensor("steps") {|me| me.steps}
556
+ @ii.register_sensor("top_int") {|me| me.pop_value(:int)}
557
+ @ii.register_sensor("second_int") {|me| me.pop_value(:int)}
558
+ 3.times {@ii.step} # so as not to fire sensors at the end
559
+ @ii.fire_all_sensors.should == {"steps"=>3, "top_int"=>11, "second_int"=>88}
560
+ end
561
+ end
562
+ end
@@ -1,3 +1,4 @@
1
+ #encoding: utf-8
1
2
  require File.join(File.dirname(__FILE__), "/../spec_helper")
2
3
  include Nudge
3
4
 
@@ -78,4 +79,38 @@ describe "stack" do
78
79
  @myStack.depth.should == 2
79
80
  end
80
81
  end
82
+
83
+
84
+ describe "inspect" do
85
+ it "should return the entries wrapped in brackets" do
86
+ inspectable_me = Stack.new(:foo)
87
+ 3.times {inspectable_me.push(ValuePoint.new("foo", rand(1000)))}
88
+ inspectable_me.inspect.first.should == "["
89
+ inspectable_me.inspect.last.should == "]"
90
+ end
91
+
92
+ it "should return them top-to-bottom" do
93
+ inspectable_me = Stack.new(:foo)
94
+ inspectable_me.push(ValuePoint.new("foo", 'bottom'))
95
+ inspectable_me.push(ValuePoint.new("foo", 'top'))
96
+ inspectable_me.inspect.should =~ /(.+)top(.+)bottom\]/um
97
+ end
98
+
99
+ it "should return a string containing every entry" do
100
+ inspectable_me = Stack.new(:foo)
101
+ (-2..2).each {|i| inspectable_me.push(ValuePoint.new("foo", i))}
102
+ (inspectable_me.inspect.scan(/(-\d|\d)/)).flatten.collect {|n| n.to_i}.should ==
103
+ [2,1,0,-1,-2]
104
+ end
105
+
106
+ it "should return the type and value of each entry" do
107
+ inspectable_me = Stack.new(:foo)
108
+ inspectable_me.push(ValuePoint.new("a", '1'))
109
+ inspectable_me.push(ValuePoint.new("b", '2'))
110
+ inspectable_me.push(ValuePoint.new("c", '3'))
111
+ inspectable_me.push(ValuePoint.new("d", '4'))
112
+
113
+ inspectable_me.inspect.should == "[\n«d» 4,\n«c» 3,\n«b» 2,\n«a» 1]"
114
+ end
115
+ end
81
116
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Bill Tozier