nudge 0.1.2 → 0.1.3

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/Rakefile CHANGED
@@ -16,8 +16,8 @@ begin
16
16
  gemspec.required_ruby_version = '>= 1.9.1'
17
17
 
18
18
  # dependencies
19
- gemspec.add_dependency('treetop', '>= 1.4.3')
20
19
  gemspec.add_dependency('activesupport', '>= 2.3.5')
20
+ gemspec.add_dependency('thor', '>= 0.13')
21
21
 
22
22
  # files
23
23
  gemspec.files.exclude '_spikes/**'
data/Thorfile ADDED
@@ -0,0 +1,59 @@
1
+ require 'active_support'
2
+
3
+ class Extend_Nudge < Thor::Group
4
+ include Thor::Actions
5
+
6
+ # Define arguments and options
7
+ argument :project_name
8
+ class_option :test_framework, :default => :rspec
9
+
10
+ def self.source_root
11
+ File.dirname(__FILE__)
12
+ end
13
+ end
14
+
15
+
16
+ class New_Nudge_Type < Thor::Group
17
+ include Thor::Actions
18
+
19
+ # Define arguments and options
20
+ argument :type_root
21
+ class_option :test_framework, :default => :rspec
22
+ desc "Creates a new NudgeType class definition file, typical instructions, and rspec files"
23
+
24
+
25
+ def self.source_root
26
+ File.dirname(__FILE__)
27
+ end
28
+
29
+ def self.type_name(string)
30
+ string.camelize + "Type"
31
+ end
32
+
33
+ def create_lib_file
34
+ @camelcased_type_name = New_Nudge_Type.type_name(type_root)
35
+ filename = "#{@camelcased_type_name}.rb"
36
+ template('templates/nudge_type_class.erb', "#{type_root}/lib/types/#{filename}")
37
+ end
38
+
39
+ def create_lib_spec
40
+ @camelcased_type_name = New_Nudge_Type.type_name(type_root)
41
+ filename = "#{@camelcased_type_name}_spec.rb"
42
+ template('templates/nudge_type_spec.erb', "#{type_root}/spec/#{filename}")
43
+ end
44
+
45
+ def create_instructions
46
+ suite = ["define", "equal_q", "duplicate", "flush", "pop",
47
+ "random", "rotate", "shove", "swap", "yank", "yankdup"]
48
+
49
+ suite.each do |inst|
50
+ @core = "#{type_root}_#{inst}"
51
+ filename = "#{@core}.rb"
52
+ @instname = "#{@core.camelize}Instruction"
53
+ @type = type_root
54
+ @camelized_type = New_Nudge_Type.type_name(type_root)
55
+ template("templates/nudge_#{inst}_instruction.erb", "#{type_root}/lib/instructions/#{filename}")
56
+ end
57
+ end
58
+
59
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
data/bin/nudge CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env ruby -U
2
2
 
3
- puts "Hi there"
3
+ puts "Hi there; not doing anything right now."
data/lib/cli/runner.rb CHANGED
@@ -14,7 +14,7 @@ module Nudge
14
14
  @filename = filename
15
15
  @nudge_program = NudgeProgram.new("")
16
16
  @options = options
17
- @interpreter = Interpreter.new(@options)
17
+ @interpreter = Interpreter.new("",@options)
18
18
  end
19
19
 
20
20
 
@@ -20,8 +20,8 @@ module Nudge
20
20
 
21
21
 
22
22
  # A program to be interpreted can be passed in as an optional parameter
23
- def initialize(params = {})
24
- initialProgram = params[:program] || nil
23
+ def initialize(program = nil, params = {})
24
+ initialProgram = program
25
25
  @program = initialProgram
26
26
  @types = params[:types] || NudgeType.all_types
27
27
  @step_limit = params[:step_limit] || 3000
@@ -57,7 +57,7 @@ module Nudge
57
57
  self.clear_stacks
58
58
  self.reset_names
59
59
  self.reset_sensors
60
- if program
60
+ if !program.nil?
61
61
  @stacks[:exec].push(NudgeProgram.new(program).linked_code)
62
62
  end
63
63
  @steps = 0
@@ -21,86 +21,19 @@ module Nudge
21
21
  def initialize(sourcecode)
22
22
  raise(ArgumentError, "NudgeProgram.new should be passed a string") unless sourcecode.kind_of?(String)
23
23
  @raw_code = sourcecode
24
- program_split!
25
- relink_code!
26
- @points = self.points
27
- end
28
-
29
-
30
-
31
-
32
-
33
- def program_split!
24
+
25
+ # snipped out:
26
+ # program_split!
34
27
  split_at_first_guillemet=@raw_code.partition( /^(?=«)/ )
35
28
  @code_section = split_at_first_guillemet[0].strip
36
29
  @footnote_section = split_at_first_guillemet[2].strip
37
- @footnotes = tokenized_footnote_section
38
- end
39
-
40
-
41
-
42
- def tokenized_footnote_section
43
- shattered = @footnote_section.split( /^(?=«)/ )
44
- breaker = /^«([a-zA-Z][a-zA-Z0-9_]*)»\s*(.*)\s*/m
45
- pairs = shattered.collect {|fn| fn.match(breaker)[1..2]}
46
- fn = Hash.new {|hash, key| hash[key] = [] }
47
- @footnote_order = []
48
- pairs.each do |key,value|
49
- fn[key.to_sym] << value.strip
50
- end
51
- return fn
52
- end
53
-
54
-
55
-
56
- def relink_code!
57
- if parses?
58
- @linked_code = NudgeCodeblockParser.new.parse(@code_section).to_point
59
- depth_first_association!
60
- else
61
- @linked_code = NilPoint.new
62
- end
63
- end
64
-
65
-
66
-
67
- def depth_first_association!(program_point=@linked_code)
68
- if program_point.kind_of?(ValuePoint)
69
- program_point.raw = @footnotes[program_point.type].shift
70
- if program_point.raw != nil
71
- if program_point.type == :code
72
- program_point.raw << pursue_more_footnotes(program_point.raw)
73
- end
74
- end
75
- elsif program_point.kind_of?(CodeblockPoint)
76
- program_point.contents.each {|branch| depth_first_association!(branch)}
77
- end
78
- end
79
-
80
-
81
-
82
- def pursue_more_footnotes(codepoint_as_string, collected_footnotes = "")
83
- local_footnotes = ""
84
- if self.contains_valuepoints?(codepoint_as_string)
85
- local_parsetree = NudgeCodeblockParser.new.parse(codepoint_as_string)
86
- if local_parsetree != nil
87
- local_subtree = local_parsetree.to_point
88
- if local_subtree.kind_of?(CodeblockPoint)
89
- local_subtree.contents.each do |branch|
90
- local_footnotes << pursue_more_footnotes(branch.tidy)
91
- end
92
- elsif local_subtree.kind_of?(ValuePoint)
93
- local_subtree.raw = @footnotes[local_subtree.type].shift
94
- if local_subtree.raw != nil
95
- local_footnotes = "\n«#{local_subtree.type}» #{local_subtree.raw}"
96
- if local_subtree.type == :code
97
- local_footnotes << pursue_more_footnotes(local_subtree.raw,collected_footnotes)
98
- end
99
- end
100
- end
101
- end
102
- end
103
- return collected_footnotes + local_footnotes
30
+
31
+ #snipped out:
32
+ #relink_code!
33
+ parsed_code = NudgeTree.from(@raw_code)
34
+ @linked_code = parsed_code[:tree]
35
+ @footnotes = parsed_code[:unused]
36
+ @points = self.points
104
37
  end
105
38
 
106
39
 
@@ -1,10 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- # DO NOT MODIFY!!!!
4
- # This file is automatically generated by racc 1.4.5
5
- # from racc grammer file "parse.y".
6
- #
7
-
8
3
  require 'racc/parser'
9
4
  require 'strscan'
10
5
 
@@ -16,30 +11,50 @@ module_eval <<'..end parse.y modeval..ida1760a43d7', 'parse.y', 22
16
11
  nt = NudgeTree.new(string)
17
12
  result = nt.send(:do_parse)
18
13
  {tree:result, unused:nt.footnotes}
14
+ rescue ParseError => exc
15
+ {tree:NilPoint.new, unused:{}}
19
16
  end
20
17
 
21
- attr_accessor :footnotes
18
+
19
+ attr_accessor :tree, :footnotes, :unused_footnotes
20
+
22
21
 
23
22
  def initialize(string)
24
23
  @tokens = []
25
24
  @string = string.strip
26
25
  @footnotes = Hash.new { |hash, category| hash[category] = [] }
27
-
26
+ @unused_footnotes = {}
28
27
  self.make_footnotes!
29
28
  self.tokenize!
30
29
  end
31
30
 
31
+
32
32
  def make_footnotes!
33
- return unless split_point = @string.index(/^«/)
33
+ return unless split_point = @string.index(/\n«/um)
34
34
  raise ParseError, "No program string" if split_point == 0
35
35
 
36
- ss = StringScanner.new(@string.slice!((split_point - 1)..-1))
36
+ ss = StringScanner.new(@string.slice!((split_point)..-1))
37
+
38
+ fn_head = /\n«([\p{Alpha}][_\p{Alnum}]*)»/u
37
39
 
38
- while ss.scan(/\n/)
39
- @footnotes[ss.scan(/«[\p{Alpha}][_\p{Alnum}]*»/u)[1..-2]] << ss.scan(/[^\n]*/).strip # <-- /\n«/
40
+ while ss.exist?(fn_head)
41
+ ss.scan_until(fn_head)
42
+ cat = ss[1]
43
+ if ss.exist?(/\n«/um)
44
+ ss.scan_until(/(.*?)\n«/um)
45
+ fn = ss[1]
46
+ elsif ss.eos?
47
+ fn = ""
48
+ else
49
+ ss.scan_until(/(.*)$/um)
50
+ fn = ss[1]
51
+ end
52
+ ss.pos -= 3
53
+ @footnotes[cat] << fn.strip
40
54
  end
41
55
  end
42
56
 
57
+
43
58
  def pop_footnote(category)
44
59
  value = @footnotes[category].shift
45
60
 
@@ -52,14 +67,14 @@ module_eval <<'..end parse.y modeval..ida1760a43d7', 'parse.y', 22
52
67
  return value
53
68
  end
54
69
 
70
+
55
71
  def collect_embedded_footnotes!(code_text, embedded_footnotes)
56
- ss = StringScanner.new(code_text)
57
-
58
- while ss.skip_until(/«[\p{Alpha}][\p{Alnum}_]*»/)
59
- category = ss.matched[1...-1]
60
- footnote = @footnotes[category].shift
72
+ ss = StringScanner.new(code_text)
73
+ while ss.skip_until(/«([\p{Alpha}][\p{Alnum}_]*?)»/um)
74
+ category = ss[1]
75
+ footnote = @footnotes[category].shift || ""
61
76
 
62
- embedded_footnotes << "«#{category}»#{footnote}"
77
+ embedded_footnotes << "«#{category}» #{footnote}"
63
78
 
64
79
  if category == "code"
65
80
  self.collect_embedded_footnotes!(footnote, embedded_footnotes)
@@ -67,10 +82,12 @@ module_eval <<'..end parse.y modeval..ida1760a43d7', 'parse.y', 22
67
82
  end
68
83
  end
69
84
 
85
+
70
86
  def next_token
71
87
  return @tokens.shift
72
88
  end
73
89
 
90
+
74
91
  def tokenize!
75
92
  ss = StringScanner.new(@string)
76
93
 
@@ -80,9 +97,9 @@ module_eval <<'..end parse.y modeval..ida1760a43d7', 'parse.y', 22
80
97
  nil
81
98
  when /[{}«»]/
82
99
  [c, 0]
83
- when /[\p{Alpha}]/
84
- ss.pointer -= 1
85
- ss.scan(/[\p{Alpha}][\p{Alnum}_]*/) # <- \p{Alpha}
100
+ when /[\p{Alpha}]/u
101
+ ss.unscan
102
+ ss.scan(/[\p{Alpha}][_\p{Alnum}]*/u) # <- \p{Alpha}
86
103
 
87
104
  case m = ss.matched
88
105
  when "block", "ref", "do", "value"
@@ -91,7 +108,7 @@ module_eval <<'..end parse.y modeval..ida1760a43d7', 'parse.y', 22
91
108
  [:ID, m]
92
109
  end
93
110
  else
94
- raise ParseError, "Couldn't tokenize program string"
111
+ raise ParseError, "Couldn't tokenize program string \"#{@string}\""
95
112
  end
96
113
  end
97
114
 
@@ -99,6 +116,7 @@ module_eval <<'..end parse.y modeval..ida1760a43d7', 'parse.y', 22
99
116
  @tokens << [false, false]
100
117
  end
101
118
 
119
+
102
120
  def on_error(error_token_id, error_value, value_stack)
103
121
  raise ParseError, "Couldn't parse program string"
104
122
  end
@@ -92,10 +92,7 @@ module Nudge
92
92
  def initialize(type,representation=nil)
93
93
  raise(ArgumentError, "Type must be a symbol or string") unless [Symbol,String].include?(type.class)
94
94
  @type = type.to_sym
95
- if representation != nil
96
- representation = representation.to_s
97
- end
98
- @raw = representation
95
+ @raw = representation.nil? ? nil : representation.to_s
99
96
  end
100
97
 
101
98
  def go(context)
@@ -147,13 +144,13 @@ module Nudge
147
144
  end
148
145
 
149
146
  def blueprint_parts
150
- fn = @raw ? "«#{self.type}» #{self.raw}" : ""
147
+ fn = "«#{self.type}» #{self.raw}".strip
151
148
  return [self.tidy, fn]
152
149
  end
153
150
 
154
151
  def blueprint
155
152
  pts = self.blueprint_parts
156
- return "value «#{self.type}» \n«#{self.type}» #{self.raw.strip}".strip
153
+ return "#{pts[0]} \n#{pts[1]}"
157
154
  end
158
155
  end
159
156
 
data/readme.md CHANGED
@@ -8,16 +8,50 @@ See the [project Wiki](http://github.com/Vaguery/Nudge/wikis) for a more thoroug
8
8
 
9
9
  ## Getting started
10
10
 
11
+ ### Ruby 1.9
12
+
13
+ Make sure your Ruby version is 1.9 (or higher) by running
14
+
15
+ ruby -v
16
+
17
+ and getting something along the lines of `ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.2.0]` as a response. If you see `ruby 1.8.7`, we'd recommend a look at [rvm](http://rvm.beginrescueend.com/).
18
+
19
+ ### Installing the gem
20
+
11
21
  gem install nudge
12
22
 
13
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…
14
24
 
15
- Meanwhile, try this:
25
+ ### A test run
26
+
27
+ Meanwhile, try something like this in irb:
16
28
 
29
+ #encoding: utf-8
30
+ # you'll need to use unicode for all Nudge programs
31
+
17
32
  require 'nudge'
18
33
  include Nudge
19
34
 
20
- my_program = Nudge.random(target_size_in_points:20) # generates
35
+ my_program = NudgeProgram.random(
36
+ :target_size_in_points => 50,
37
+ :reference_names => ["x1", "x2"])
38
+
39
+ puts "Your random program:\n\n#{my_program.blueprint}"
40
+
41
+ my_interpreter = Interpreter.new()
42
+
43
+ my_interpreter.reset(my_program.blueprint)
44
+
45
+
46
+ # set up some sensors, so we know what happens afterwards
47
+ my_interpreter.register_sensor("int_1") {|state| state.peek_value(:int)} # reads the top :int value
48
+ my_interpreter.register_sensor("bool_1") {|state| state.peek_value(:bool)} # reads the top :bool value
49
+ my_interpreter.register_sensor("steps") {|state| state.steps} # reads the number of steps the interpreter took
50
+
51
+ puts "\n\nsensor values: #{my_interpreter.run}"
52
+
53
+ When you run that, you'll get something [like this](http://gist.github.com/347215)—though your code and output will (hopefully) be a different random result!
54
+
21
55
  ## Requirements
22
56
 
23
57
  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,51 @@
1
+ #encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), "./../spec_helper")
3
+ include Nudge
4
+
5
+ describe "thor new_nudge_type MY_TYPE" do
6
+ before(:each) do
7
+ end
8
+
9
+ describe "documentation" do
10
+ it "should have a desc field"
11
+ end
12
+
13
+
14
+ describe "validating type names" do
15
+ it "should check to see the type_name matches the allowed pattern"
16
+
17
+ it "should quit and warn you if it doesn't match"
18
+ end
19
+
20
+
21
+ describe "checking for preexisting files" do
22
+ it "should ask if you already have something there"
23
+
24
+ it "should replace it without asking if you use '--force'"
25
+
26
+ it "should replace it if you answer 'yes'"
27
+ end
28
+
29
+
30
+ describe "creating core lib/MyType.rb file" do
31
+ it "should use template 'templates/nudge_type_class.tt"
32
+
33
+
34
+ it "should require 'nudge'"
35
+
36
+ end
37
+
38
+
39
+ describe "creating boilerplate instruction code" do
40
+ it "should make lib/instructions/foo_define.rb"
41
+ it "should make lib/instructions/foo_equal_q.rb"
42
+ it "should make lib/instructions/foo_duplicate.rb"
43
+ it "should make lib/instructions/foo_flush.rb"
44
+ it "should make lib/instructions/foo_pop.rb"
45
+ it "should make lib/instructions/foo.random.rb" # if it's a candidate for literals
46
+ it "should make lib/instructions/foo_rotate.rb"
47
+ it "should make lib/instructions/foo_shove.rb"
48
+ it "should make lib/instructions/foo_swap.rb"
49
+ it "should make lib/instructions/foo_yank.rb"
50
+ end
51
+ end
@@ -26,7 +26,7 @@ describe CodeNoopInstruction do
26
26
 
27
27
  describe "\#cleanup" do
28
28
  it "should change nothing about the interpreter except the step count" do
29
- @context = Interpreter.new(program:"do code_noop")
29
+ @context = Interpreter.new("do code_noop")
30
30
  @context.enable(CodeNoopInstruction)
31
31
  earlier = @context.steps
32
32
  @context.run
@@ -3,8 +3,7 @@ require File.join(File.dirname(__FILE__), "/../spec_helper")
3
3
  include Nudge
4
4
 
5
5
  def magicCodeblockPointMaker(program_blueprint)
6
- my_kludge = NudgeProgram.new(program_blueprint)
7
- return my_kludge.linked_code
6
+ NudgeTree.from(program_blueprint)[:tree]
8
7
  end
9
8
 
10
9
 
@@ -43,10 +42,10 @@ describe "blueprint_parts" do
43
42
  context "when there need to be footnotes" do
44
43
  it "should work for blocks containing nil-valued ValuePoints" do
45
44
  CodeblockPoint.new([ValuePoint.new("foo")]).blueprint_parts.should ==
46
- ["block {\n value «foo»}",""]
45
+ ["block {\n value «foo»}","«foo»"]
47
46
  annoyinglyWordy = magicCodeblockPointMaker("block { block { block { value «foo»}}}")
48
47
  annoyinglyWordy.blueprint_parts.should ==
49
- ["block {\n block {\n block {\n value «foo»}}}",""]
48
+ ["block {\n block {\n block {\n value «foo»}}}","«foo»"]
50
49
  end
51
50
 
52
51
  it "should work with footnotes from the root" do
@@ -65,8 +65,8 @@ describe "initialization" do
65
65
  end
66
66
 
67
67
  it "should accept a blueprint, which should default to an empty string" do
68
- Interpreter.new(program:"value «int» \n«int» 7").program.should == "value «int» \n«int» 7"
69
- # Interpreter.new().program.should == ""
68
+ Interpreter.new("value «int» \n«int» 7").program.should == "value «int» \n«int» 7"
69
+ Interpreter.new().program.should == nil
70
70
  end
71
71
 
72
72
  it "should have an #enable method that works for Instructions, adding them to the #instructions hash" do
@@ -444,7 +444,6 @@ describe "running" do
444
444
 
445
445
  it "should do nothing if the :exec stack starts empty" do
446
446
  @ii.reset()
447
- puts @ii.stacks[:exec].depth
448
447
  @ii.run
449
448
  @ii.steps.should == 0
450
449
  end
@@ -461,7 +460,7 @@ end
461
460
 
462
461
  describe "resetting" do
463
462
  it "should clear the steps" do
464
- ii = Interpreter.new(program:"block {ref a ref b}")
463
+ ii = Interpreter.new("block {ref a ref b}")
465
464
  ii.run
466
465
  ii.steps.should == 3
467
466
  ii.reset
@@ -484,7 +483,7 @@ describe "resetting" do
484
483
  end
485
484
 
486
485
  it "should clear the program, if none is given" do
487
- ii = Interpreter.new(program:"block {}")
486
+ ii = Interpreter.new("block {}")
488
487
  ii.reset
489
488
  ii.program.should == nil
490
489
  end