linguify 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -172,7 +172,7 @@ end
172
172
 
173
173
  (The MIT License)
174
174
 
175
- Copyright (c) 2011 Patrick Hanevold
175
+ Copyright (c) 2011-2012 Patrick Hanevold
176
176
 
177
177
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
178
178
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.1
1
+ 0.5.2
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Copyright (c) 2011 Patrick Hanevold.
3
+ # Copyright (c) 2011-2012 Patrick Hanevold.
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -49,40 +49,34 @@ module Linguify
49
49
  :lang => rule[:lang],
50
50
  :inline => rule[:inline],
51
51
  :regexp => rule[:match].inspect,
52
- :args => rule[:match].match(str).to_a[1..-1]
52
+ :args => rule[:match].match(str).to_a
53
53
 
54
54
  str = Linguified.reduce_string(str,rule[:match],reduction.to_rexp)
55
- break if /^{.*}$/ =~ str
55
+ break if /^{:[0-9]*}$/ =~ str
56
56
  end
57
57
 
58
- @encoded = str
59
-
60
58
  @merged_code = []
61
- if /^{(?<code>.*)}$/ =~ @encoded
62
- # successfully reduced entire string, compile it
63
- code = Reduction::parse(code).compile
64
-
65
- # and wrap it up
66
- @sexy = Sexp.new(:block,
67
- Sexp.new(:lasgn,:code, Sexp.new(:iter,
68
- Sexp.new(:call, nil, :lambda, Sexp.new(:arglist)), nil,
69
- Sexp.new(:block,
70
- *code
71
- )
72
- )
59
+
60
+ #
61
+ # successfully reduced entire string, compile it
62
+ #
63
+
64
+ code = Reduction::parse(str).compile
65
+
66
+ #if @dispatch_exceptions
67
+ # @sexy = Sexp.debug_envelope(code)
68
+ #else
69
+ @sexy = Sexp.lambda_envelope(code)
70
+ #end
71
+
72
+ # let ruby compile a proc out of the actual code
73
+ # the trampoline function will receive the compiled Proc
74
+ @@me = self
75
+ eval to_ruby(
76
+ Sexp.new(:call,
77
+ Sexp.new(:colon2, Sexp.new(:const, :Linguify), :Linguified), :trampoline, Sexp.new(:arglist, Sexp.new(:lvar, :code))
73
78
  )
74
- )
75
-
76
- @@me = self
77
- eval to_ruby(
78
- Sexp.new(:call,
79
- Sexp.new(:colon2, Sexp.new(:const, :Linguify), :Linguified), :trampoline, Sexp.new(:arglist, Sexp.new(:lvar, :code))
80
- )
81
- ),bind
82
- raise "hell" unless @proc
83
- else
84
- raise "hell"
85
- end
79
+ ),bind
86
80
  end
87
81
 
88
82
  # Reduce a string with a matching reduction expression
@@ -94,9 +88,9 @@ module Linguify
94
88
  #
95
89
  def self.reduce_string str,match_expression,reduction
96
90
  match = match_expression.match(str).to_a
91
+ needle = match.first
92
+ splitted = Linguified.informative_split(str,needle)
97
93
  if match.size == 1
98
- needle = match[0]
99
- splitted = Linguified.informative_split(str,needle)
100
94
  prev = ' '
101
95
  i = -1
102
96
  splitted.map! do |split|
@@ -115,9 +109,6 @@ module Linguify
115
109
  end
116
110
  splitted.join
117
111
  else
118
- needle = match[0]
119
- splitted = Linguified.informative_split(str,needle)
120
-
121
112
  splitted.map{ |split| split.kind_of?(Symbol) ? reduction : split }.join
122
113
  end
123
114
  end
@@ -149,6 +140,8 @@ module Linguify
149
140
  # @returns [ Boolean ] true if so
150
141
  #
151
142
  def self.has_needle_on_word_boundary? splitted
143
+ return true if splitted.size == 1 and splitted.first == :needle
144
+
152
145
  splitted.each_with_index do |split,i|
153
146
  if split.kind_of? String
154
147
  word_bound = i == 0 ? split[-1] == ' ' : split[0] == ' ' || split[-1] == ' '
@@ -167,21 +160,13 @@ module Linguify
167
160
  if rule[:match] =~ str
168
161
  # ok, it matched, but only alow matches with word boundaries
169
162
  match = rule[:match].match(str).to_a
170
- if match.size == 1
171
- # one match means the search space contains just the needle, so its a perfect match
172
- true
173
- else
174
- # multiple matches, check if the needle is found on word boundaries
175
- raise "uh?" unless match.size == 2
176
- needle = match[1]
177
- Linguified.has_needle_on_word_boundary? Linguified.informative_split(str,needle)
178
- end
163
+ needle = match.first
164
+ Linguified.has_needle_on_word_boundary? Linguified.informative_split(str,needle)
179
165
  else
180
166
  false
181
167
  end
182
168
  end
183
169
  raise "no step definition for #{str}" if found.size == 0
184
-
185
170
  found[0]
186
171
  end
187
172
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Copyright (c) 2011 Patrick Hanevold.
3
+ # Copyright (c) 2011-2012 Patrick Hanevold.
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -82,7 +82,11 @@ module Linguify
82
82
  raise "unsupported argument type #{args}"
83
83
  end
84
84
  end
85
- @named_args = Hash[*args.zip(@args).flatten] if args
85
+
86
+ # maybe we can fix the input so we don't have to repair it here?
87
+ @args = @args[-args.size..-1] if args and args.size != @args.size
88
+
89
+ @named_args = Hash[*args.zip(@args[-args.size..-1]).flatten] if args
86
90
  @named_args ||= {}
87
91
  end
88
92
 
@@ -104,6 +108,15 @@ module Linguify
104
108
  compile_with_return_to_var
105
109
  end
106
110
 
111
+ def allocate_variable name,not_in
112
+ n = 0
113
+ begin
114
+ var = "#{name}_#{n}".to_sym
115
+ n += 1
116
+ end while not_in.select{ |sexp| sexp.variable_exists?(var) }.size > 0
117
+ var
118
+ end
119
+
107
120
  # Compile self
108
121
  #
109
122
  # @param [ Symbol,nil ] return_variable The variable in the code wanting the result.
@@ -141,16 +154,18 @@ module Linguify
141
154
  code = red.compile_with_return_to_var :replace => replace
142
155
  replace[args[i]] = Replacement.new(:sexp => Sexp.new(:block,*code), :inline => true)
143
156
  else
144
- code = red.compile_with_return_to_var :return_variable => "#{ret}_#{n}".to_sym, :replace => replace
157
+ var = allocate_variable(ret,[*args_code,sexp])
158
+ code = red.compile_with_return_to_var :return_variable => var, :replace => replace
145
159
  args_code += code
146
- replace[args[i]] = Replacement.new(:sexp => "#{ret}_#{n}".to_sym)
160
+ replace[args[i]] = Replacement.new(:sexp => var)
147
161
  end
148
162
  end
149
163
  elsif /^[0-9]+$/ =~ arg
150
164
  # got a number argument, stuff it in a integer variable
151
165
  args_code << Sexp.new(:lasgn, args[i], Sexp.new(:lit, arg.to_i))
152
166
  else
153
- raise "hell"
167
+ # got a string
168
+ replace[args[i]] = Replacement.new(:sexp => Sexp.new(:str, arg)) if args[i]
154
169
  end
155
170
  end
156
171
 
data/lib/linguify/sexp.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Copyright (c) 2011 Patrick Hanevold.
3
+ # Copyright (c) 2011-2012 Patrick Hanevold.
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -30,7 +30,7 @@ class Sexp < Array
30
30
  # @param [ Hash ] named_args The arguments of the code block
31
31
  #
32
32
  def replace_variable_references! params
33
-
33
+
34
34
  replacement = params[:replacement]
35
35
  needle = params[:needle]
36
36
  named_args = params[:named_args] || ''
@@ -41,7 +41,12 @@ class Sexp < Array
41
41
  when :lvar
42
42
  if self[1] == needle
43
43
  unless replacement.inline?
44
- self[1]=replacement.sexp
44
+ if replacement.sexp[0] == :str
45
+ self[0] = :str
46
+ self[1]=replacement.sexp[1]
47
+ else
48
+ self[1]=replacement.sexp
49
+ end
45
50
  end
46
51
  end
47
52
  when :call
@@ -81,5 +86,65 @@ class Sexp < Array
81
86
  end
82
87
  end
83
88
 
89
+ # Envelope a Sexp in a lambda
90
+ #
91
+ # @param [ Sexp ] code The Sexp to envelope
92
+ # @returns [ Sexp ] result The enveloped sexp
93
+ #
94
+ def self.lambda_envelope code
95
+ # and wrap it up in a lambda envelope for the sexp representation
96
+ Sexp.new(:block,
97
+ Sexp.new(:lasgn,:code, Sexp.new(:iter,
98
+ Sexp.new(:call, nil, :lambda, Sexp.new(:arglist)), nil,
99
+ Sexp.new(:block,
100
+ *code
101
+ )
102
+ )
103
+ )
104
+ )
105
+ end
106
+
107
+ def variable_exists? needle
108
+ case sexp_type
109
+ when :lasgn
110
+ self[1] == needle
111
+ when :lvar
112
+ self[1] == needle
113
+ when :call
114
+ self[2] == needle
115
+ when :lvar
116
+ self[1] == needle
117
+ else
118
+ self[1..-1].each do |h|
119
+ if h && h.kind_of?(Sexp)
120
+ return true if h.variable_exists?(needle)
121
+ end
122
+ end
123
+ false
124
+ end
125
+ end
126
+
127
+ ##
128
+ ## currently not in use
129
+ ## 1.9.2 p180 doesn't give us a backtrace from the other side
130
+ ##
131
+ # Envelope a Sexp in the debug envelope
132
+ # which basicly dispatch exceptions into our unitverse
133
+ #
134
+ # @param [ Sexp ] code The Sexp to envelope
135
+ # @returns [ Sexp ] result The enveloped sexp
136
+ #
137
+ #def self.debug_envelope code
138
+ # Sexp.new(:block,
139
+ # Sexp.new(:lasgn,:code, Sexp.new(:iter,
140
+ # Sexp.new(:call, nil, :lambda, Sexp.new(:arglist)), nil,
141
+ # Sexp.new(:rescue,
142
+ # Sexp.new(:block,*code),
143
+ # Sexp.new(:resbody,
144
+ # Sexp.new(:array, Sexp.new(:const, :Exception), Sexp.new(:lasgn, :e, Sexp.new(:gvar, :$!))),
145
+ # Sexp.new(:call, Sexp.new(:const, :Linguify), :exception, Sexp.new(:arglist, Sexp.new(:lvar, :e))))))))
146
+ #end
147
+
148
+
84
149
  end
85
150
 
data/lib/linguify.rb CHANGED
@@ -87,6 +87,12 @@ module Linguify
87
87
  @@rules ||= []
88
88
  end
89
89
 
90
+ # currently not in use
91
+ # 1.9.2 p180 doesn't give us a backtrace from the other side
92
+ #def self.exception e
93
+ # raise e
94
+ #end
95
+
90
96
  end
91
97
 
92
98
 
data/linguify.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "linguify"
8
- s.version = "0.5.1"
8
+ s.version = "0.5.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Patrick Hanevold"]
12
- s.date = "2012-01-13"
12
+ s.date = "2012-01-15"
13
13
  s.description = "Linguify is a linguistic compiler allowing you to compile and execute plain english."
14
14
  s.email = "patrick.hanevold@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,11 @@ require 'linguify'
25
25
 
26
26
  describe Linguify::Linguified, "#linguify" do
27
27
 
28
+ before(:each) do
29
+ Linguify::Reduction.class_variable_set(:@@reductions,[])
30
+ Linguify.class_variable_set(:@@rules,[])
31
+ end
32
+
28
33
  it "finds words in sentences" do
29
34
  l = Linguify::Linguified
30
35
  l.informative_split("I fight for the users","users").should == ["I fight for the ", :needle]
@@ -47,6 +52,53 @@ describe Linguify::Linguified, "#linguify" do
47
52
  l.reduce_string('I fight for a user with email "user@domain.com"',/user/,"{needle}").should == 'I fight for a {needle} with email "user@domain.com"'
48
53
  end
49
54
 
55
+ it "handles multiple arguments of same kind" do
56
+
57
+ reduce /word/ => 'a_word' do
58
+ "word".to_a
59
+ end
60
+
61
+ reduce /a ({a_word:[^}]*}) is a ({a_word:[^}]*})/ do |word_a,word_b|
62
+ word_a.zip(word_b)
63
+ end
64
+
65
+ "a word is a word".linguify.to_ruby.should == "code = lambda do\n a_word_0 = \"word\".to_a\n a_word_1 = \"word\".to_a\n a_word_0.zip(a_word_1)\nend\n"
66
+ end
67
+
68
+ it "handles aliases" do
69
+
70
+ reduce /word/ => 'word' do |word|
71
+ word
72
+ end
73
+
74
+ reduce /({word:[^}]*})/ => 'alias' do |a|
75
+ a
76
+ end
77
+
78
+ reduce /({alias:[^}]*})/ do |b|
79
+ b
80
+ end
81
+
82
+ "word".linguify.to_ruby.should == "code = lambda do\n word_0 = \"word\"\n alias_0 = word_0\n alias_0\nend\n"
83
+ end
84
+
85
+ it "handles this" do
86
+
87
+ reduce /user/ => 'model' do |model|
88
+ model.to_s
89
+ end
90
+ reduce /the ({model:[^}]*})/ => 'the_object' do |model|
91
+ model
92
+ end
93
+ reduce /And ({the_object:[^}]*}) is a ([^ ]*) ({model:[^}]*})/ do |mod,type,is|
94
+ mod.to_a
95
+ type.to_f
96
+ end
97
+
98
+ "And the user is a real user".linguify.to_ruby.should == "code = lambda do\n model_0 = \"user\".to_s\n the_object_0 = model_0\n model_1 = \"user\".to_s\n (the_object_0.to_a\n \"real\".to_f)\nend\n"
99
+ end
100
+
101
+
50
102
  it "should reduce multiple rules into ruby code" do
51
103
 
52
104
  reduce /all directories/ => 'directories' do
@@ -78,7 +130,7 @@ describe Linguify::Linguified, "#linguify" do
78
130
  end
79
131
  end
80
132
 
81
- "view all files inside all directories recursively".linguify.to_ruby.should == "code = lambda do\n directories_0 = Dir.entries(\".\").select { |f| (not (f[0] == \".\")) and File.directory?(f) }\n directories_1 = (all_dirs = directories_0\n Find.find(directories_0) do |path|\n if FileTest.directory?(path) then\n if (File.basename(path)[0] == \".\") then\n Find.prune\n else\n (all_dirs << path)\n next\n end\n end\n end\n all_dirs)\n files_2 = directories_1.map { |f| File.new(f, \"r\") }\n files_2.each { |file| pp(file) }\nend\n"
133
+ "view all files inside all directories recursively".linguify.to_ruby.should == "code = lambda do\n directories_0 = Dir.entries(\".\").select { |f| (not (f[0] == \".\")) and File.directory?(f) }\n directories_0 = (all_dirs = directories_0\n Find.find(directories_0) do |path|\n if FileTest.directory?(path) then\n if (File.basename(path)[0] == \".\") then\n Find.prune\n else\n (all_dirs << path)\n next\n end\n end\n end\n all_dirs)\n files_0 = directories_0.map { |f| File.new(f, \"r\") }\n files_0.each { |file| pp(file) }\nend\n"
82
134
  end
83
135
 
84
136
  it "should mix javascript and ruby" do
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: linguify
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.5.1
5
+ version: 0.5.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Patrick Hanevold
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-01-13 00:00:00 Z
13
+ date: 2012-01-15 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sourcify
@@ -115,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
115
  requirements:
116
116
  - - ">="
117
117
  - !ruby/object:Gem::Version
118
- hash: -1602177770022402179
118
+ hash: 914071381584343177
119
119
  segments:
120
120
  - 0
121
121
  version: "0"