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 CHANGED
@@ -17,7 +17,6 @@ begin
17
17
 
18
18
  # dependencies
19
19
  gemspec.add_dependency('activesupport', '>= 2.3.5')
20
- gemspec.add_dependency('thor', '>= 0.13')
21
20
 
22
21
  # files
23
22
  gemspec.files.exclude '_spikes/**'
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.3
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 <b>:exec</b> Stack
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 <b>:exec</b>
124
- # 3. call its go() method
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. S Real Soon Now, it'll be part of a more interesting gem…
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
- - 3
9
- version: 0.2.3
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-09 00:00:00 -04:00
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: