nudge 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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