nudge 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +0 -1
- data/Thorfile +17 -1
- data/VERSION +1 -1
- data/lib/interpreter/interpreter.rb +59 -7
- data/readme.md +1 -1
- metadata +3 -16
data/Rakefile
CHANGED
data/Thorfile
CHANGED
@@ -6,10 +6,26 @@ class Extend_Nudge < Thor::Group
|
|
6
6
|
# Define arguments and options
|
7
7
|
argument :project_name
|
8
8
|
class_option :test_framework, :default => :rspec
|
9
|
-
|
9
|
+
desc "Creates a new project folder structure for Nudge types, instructions and specs"
|
10
|
+
|
11
|
+
|
10
12
|
def self.source_root
|
11
13
|
File.dirname(__FILE__)
|
12
14
|
end
|
15
|
+
|
16
|
+
def create_project_folder
|
17
|
+
dirname = "#{Extend_Nudge.source_root}/#{project_name}"
|
18
|
+
puts dirname
|
19
|
+
if Dir.exist?(dirname) then
|
20
|
+
puts "project directory 'dirname' already exists"
|
21
|
+
else
|
22
|
+
empty_directory(dirname)
|
23
|
+
empty_directory("#{dirname}/lib")
|
24
|
+
empty_directory("#{dirname}/lib/instructions")
|
25
|
+
empty_directory("#{dirname}/lib/interpreter/types")
|
26
|
+
empty_directory("#{dirname}/spec")
|
27
|
+
end
|
28
|
+
end
|
13
29
|
end
|
14
30
|
|
15
31
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.4
|
@@ -2,16 +2,20 @@
|
|
2
2
|
module Nudge
|
3
3
|
|
4
4
|
# The Interpreter class executes the Push3-like language loop:
|
5
|
-
# 1. Pop the top item off the <
|
5
|
+
# 1. Pop the top item off the <tt>:exec</tt> Stack
|
6
6
|
# 2. If it is a(n)...
|
7
7
|
# * ... InstructionPoint, execute that instruction's go() method;
|
8
8
|
# * ... ValuePoint, push its value to the Stack it names;
|
9
|
-
# * ... ReferencePoint (Variable or Name), ...
|
9
|
+
# * ... ReferencePoint (a reference to a Variable or Name), ...
|
10
10
|
# * ... if it's bound to a value, push the bound value onto the <b>:exec</b> Stack;
|
11
11
|
# * ... if it's not bound, push the name itself onto the <b>:name</b> Stack;
|
12
12
|
# * ... CodeblockPoint, push its #contents (in the same order) back onto the <b>:exec</b> Stack
|
13
13
|
# * ... NilPoint, do nothing
|
14
|
-
|
14
|
+
#
|
15
|
+
# This cycle repeats until one of the termination conditions is met:
|
16
|
+
# * nothing more remains on the <tt>:exec/tt> stack
|
17
|
+
# * the number of cycles meets or exceeds the <tt>step_limit</tt>
|
18
|
+
# * the wall-clock time meets or exceeds the <tt>time_limit</tt>
|
15
19
|
class Interpreter
|
16
20
|
attr_accessor :program, :step_limit, :steps
|
17
21
|
attr_accessor :stacks, :instructions_library, :variables, :names, :types
|
@@ -21,7 +25,6 @@ module Nudge
|
|
21
25
|
attr_accessor :start_time, :time_limit
|
22
26
|
|
23
27
|
|
24
|
-
# A program to be interpreted can be passed in as an optional parameter
|
25
28
|
def initialize(program = nil, params = {})
|
26
29
|
initialProgram = program
|
27
30
|
@program = initialProgram
|
@@ -55,7 +58,10 @@ module Nudge
|
|
55
58
|
# * parses the program
|
56
59
|
# * if it parses, pushes it onto the <b>:exec</b> Stack
|
57
60
|
# * (and if it doesn't parse, leaves all stacks empty)
|
58
|
-
# * resets the @step counter
|
61
|
+
# * resets the @step counter
|
62
|
+
# * resets the name assignments
|
63
|
+
# * resets the start_time (intentional redundancy)
|
64
|
+
# * resets a number of state variables
|
59
65
|
def reset(program=nil)
|
60
66
|
@program = program
|
61
67
|
self.clear_stacks
|
@@ -70,38 +76,46 @@ module Nudge
|
|
70
76
|
end
|
71
77
|
|
72
78
|
|
79
|
+
|
80
|
+
# Deletes all items from all stacks
|
73
81
|
def clear_stacks
|
74
82
|
@stacks = Hash.new {|hash, key| hash[key] = Stack.new(key) }
|
75
83
|
end
|
76
84
|
|
77
85
|
|
86
|
+
# Returns the count of items in a given stack
|
78
87
|
def depth(stackname)
|
79
88
|
@stacks[stackname].depth
|
80
89
|
end
|
81
90
|
|
82
91
|
|
92
|
+
# Returns a link to the top item in a given stack (not its value)
|
83
93
|
def peek(stackname)
|
84
94
|
@stacks[stackname].peek
|
85
95
|
end
|
86
96
|
|
87
97
|
|
98
|
+
# Returns a link to the value of the top item in a given stack
|
88
99
|
def peek_value(stackname)
|
89
100
|
item = @stacks[stackname].peek
|
90
101
|
item.nil? ? nil : item.value
|
91
102
|
end
|
92
103
|
|
93
104
|
|
105
|
+
# Removes the top item from a given stack and returns it
|
94
106
|
def pop(stackname)
|
95
107
|
@stacks[stackname].pop
|
96
108
|
end
|
97
109
|
|
98
110
|
|
111
|
+
# Removes the top item from a given stack and returns its value
|
99
112
|
def pop_value(stackname)
|
100
113
|
item = @stacks[stackname].pop
|
101
114
|
item.nil? ? nil : item.value
|
102
115
|
end
|
103
116
|
|
104
117
|
|
118
|
+
# Adds a new ValuePoint item, with the given value, to the named stack
|
105
119
|
def push(stackname, value="")
|
106
120
|
@stacks[stackname].push(ValuePoint.new(stackname, value))
|
107
121
|
end
|
@@ -111,6 +125,7 @@ module Nudge
|
|
111
125
|
# Checks to see if either stopping condition applies:
|
112
126
|
# 1. Is the <b>:exec</b> stack empty?
|
113
127
|
# 2. Are the number of steps greater than self.step_limit?
|
128
|
+
# 3. Has the total time since recorded self.start_time exceeded self.time_limit?
|
114
129
|
def notDone?
|
115
130
|
@stacks[:exec].depth > 0 &&
|
116
131
|
@steps < @step_limit &&
|
@@ -120,9 +135,12 @@ module Nudge
|
|
120
135
|
|
121
136
|
# Execute one cycle of the Push3 interpreter rule:
|
122
137
|
# 1. check termination conditions with self.notDone()?
|
123
|
-
# 2. pop one item from <
|
124
|
-
# 3. call
|
138
|
+
# 2. pop one item from <tt>:exec</tt>
|
139
|
+
# 3. call that item's #go method
|
125
140
|
# 4. increment the step counter self#steps
|
141
|
+
#
|
142
|
+
# Note that the start_time attribute is not adjusted; if called a long time after resetting,
|
143
|
+
# it may time out unexpectedly.
|
126
144
|
def step
|
127
145
|
if notDone?
|
128
146
|
nextPoint = @stacks[:exec].pop
|
@@ -132,6 +150,7 @@ module Nudge
|
|
132
150
|
end
|
133
151
|
|
134
152
|
|
153
|
+
# Returns an Array containing the class names of all <i>active</i> instructions
|
135
154
|
def instructions
|
136
155
|
@instructions_library.keys
|
137
156
|
end
|
@@ -147,16 +166,23 @@ module Nudge
|
|
147
166
|
end
|
148
167
|
|
149
168
|
|
169
|
+
# given a string, checks the hash of defined variables, then the names (local variables),
|
170
|
+
# returning the bound value, or nil if it is not found
|
150
171
|
def lookup(name)
|
151
172
|
@variables[name] || @names[name]
|
152
173
|
end
|
153
174
|
|
154
175
|
|
176
|
+
# returns an Array of all strings defined as variables or names
|
155
177
|
def references
|
156
178
|
@names.merge(@variables).keys
|
157
179
|
end
|
158
180
|
|
159
181
|
|
182
|
+
# Convenience method that can be called with either an Instruction or NudgeType class as an
|
183
|
+
# argument. If an Instruction, that class is added to the Interpreter's #instruction_library.
|
184
|
+
# If a NudgeType, that class is added to the list of types that can be used to generate
|
185
|
+
# random code.
|
160
186
|
def enable(item)
|
161
187
|
if item.superclass == Instruction
|
162
188
|
@instructions_library[item] = item.new(self)
|
@@ -166,6 +192,8 @@ module Nudge
|
|
166
192
|
end
|
167
193
|
|
168
194
|
|
195
|
+
# Convenience method that checks to see whether an Instruction or NudgeType class is currently
|
196
|
+
# in the active state. Returns a boolean.
|
169
197
|
def active?(item)
|
170
198
|
if item.superclass == Instruction
|
171
199
|
@instructions_library.include?(item)
|
@@ -175,6 +203,7 @@ module Nudge
|
|
175
203
|
end
|
176
204
|
|
177
205
|
|
206
|
+
# Given a string and a ProgramPoint, binds a variable with that name to that ProgramPoint
|
178
207
|
def bind_variable(name, value)
|
179
208
|
raise(ArgumentError, "Variables can only be bound to ProgramPoints") unless
|
180
209
|
value.kind_of?(ProgramPoint)
|
@@ -182,6 +211,7 @@ module Nudge
|
|
182
211
|
end
|
183
212
|
|
184
213
|
|
214
|
+
# Given a string and a ProgramPoint, binds a name with that name to that ProgramPoint
|
185
215
|
def bind_name(name, value)
|
186
216
|
raise(ArgumentError, "Names can only be bound to ProgramPoints") unless
|
187
217
|
value.kind_of?(ProgramPoint)
|
@@ -189,31 +219,38 @@ module Nudge
|
|
189
219
|
end
|
190
220
|
|
191
221
|
|
222
|
+
# generates an arbitrary string for naming new local variables, by incrememnting
|
223
|
+
# from the starting point "aaa001"
|
192
224
|
def next_name
|
193
225
|
@last_name = @last_name.next
|
194
226
|
end
|
195
227
|
|
196
228
|
|
229
|
+
# removes the named global variable from the Hash that defines them
|
197
230
|
def unbind_variable(name)
|
198
231
|
@variables.delete(name)
|
199
232
|
end
|
200
233
|
|
201
234
|
|
235
|
+
# removes the named local variable from the Hash that defines them
|
202
236
|
def unbind_name(name)
|
203
237
|
@names.delete(name)
|
204
238
|
end
|
205
239
|
|
206
240
|
|
241
|
+
# removes all global variable definitions
|
207
242
|
def reset_variables
|
208
243
|
@variables = Hash.new
|
209
244
|
end
|
210
245
|
|
211
246
|
|
247
|
+
# removes all local variable definitions
|
212
248
|
def reset_names
|
213
249
|
@names = Hash.new
|
214
250
|
end
|
215
251
|
|
216
252
|
|
253
|
+
# activates every Instruction subclass defined in any library
|
217
254
|
def enable_all_instructions
|
218
255
|
Instruction.all_instructions.each do |i|
|
219
256
|
@instructions_library[i] = i.new(self)
|
@@ -221,11 +258,16 @@ module Nudge
|
|
221
258
|
end
|
222
259
|
|
223
260
|
|
261
|
+
# activates every NudgeType subclass defined in any library
|
224
262
|
def enable_all_types
|
225
263
|
@types = NudgeType.all_types
|
226
264
|
end
|
227
265
|
|
228
266
|
|
267
|
+
# Convenience method that can be called with either an Instruction or NudgeType class as an
|
268
|
+
# argument. If an Instruction, that class is removed from the Interpreter's #instruction_library.
|
269
|
+
# If a NudgeType, that class is removed to the list of types that can be used to generate
|
270
|
+
# random code.
|
229
271
|
def disable(item)
|
230
272
|
if item.superclass == Instruction
|
231
273
|
@instructions_library.delete(item)
|
@@ -235,27 +277,37 @@ module Nudge
|
|
235
277
|
end
|
236
278
|
|
237
279
|
|
280
|
+
# Completely empties the set of active Instructions. The interpreter will recognize InstructionPoints,
|
281
|
+
# but will not invoke their #go methods when it does.
|
238
282
|
def disable_all_instructions
|
239
283
|
@instructions_library = Hash.new
|
240
284
|
end
|
241
285
|
|
242
286
|
|
287
|
+
# Completely empties the set of NudgeTypes in play. ValuePoints the Interpreter encounters will
|
288
|
+
# still be recognized in code, and will still be pushed to the appropriate stack, but new
|
289
|
+
# ValuePoints (made by various code-generating methods) will not be created.
|
243
290
|
def disable_all_types
|
244
291
|
@types = []
|
245
292
|
end
|
246
293
|
|
247
294
|
|
295
|
+
# Create a new sensor with the given name, binding the associated block argument. All sensors are
|
296
|
+
# called, in the order registered, when the Interpreter#run cycle terminates normally.
|
248
297
|
def register_sensor(name, &block)
|
249
298
|
raise(ArgumentError, "Sensor name #{name} is not a string") unless name.kind_of?(String)
|
250
299
|
@sensors[name] = block
|
251
300
|
end
|
252
301
|
|
253
302
|
|
303
|
+
# Delete all sensors.
|
254
304
|
def reset_sensors
|
255
305
|
@sensors = Hash.new
|
256
306
|
end
|
257
307
|
|
258
308
|
|
309
|
+
# Iterates through the Interpreter#sensors hash, #calling each one and passing in the current state
|
310
|
+
# of the Interpreter as an argument
|
259
311
|
def fire_all_sensors
|
260
312
|
@sensors.inject({}) do |result, (key, value)|
|
261
313
|
result[key] = @sensors[key].call(self)
|
data/readme.md
CHANGED
@@ -20,7 +20,7 @@ and getting something along the lines of `ruby 1.9.1p378 (2010-01-10 revision 26
|
|
20
20
|
|
21
21
|
gem install nudge
|
22
22
|
|
23
|
-
As of this writing, the `nudge` gem can be used as a library in your Ruby programs.
|
23
|
+
As of this writing, the `nudge` gem can be used as a library in your Ruby programs. So Real Soon Now, it'll be part of a more interesting gem…
|
24
24
|
|
25
25
|
### A test run
|
26
26
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 4
|
9
|
+
version: 0.2.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bill Tozier
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-04-
|
19
|
+
date: 2010-04-27 00:00:00 -04:00
|
20
20
|
default_executable: nudge
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -33,19 +33,6 @@ dependencies:
|
|
33
33
|
version: 2.3.5
|
34
34
|
type: :runtime
|
35
35
|
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: thor
|
38
|
-
prerelease: false
|
39
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
- 13
|
46
|
-
version: "0.13"
|
47
|
-
type: :runtime
|
48
|
-
version_requirements: *id002
|
49
36
|
description: Provides a Ruby library & CLI implementing a flexible Nudge Language interpreter, plus a set of generators for adding domain-specific instructions and types.
|
50
37
|
email: bill@vagueinnovation.com
|
51
38
|
executables:
|