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 +1 -1
- data/VERSION +1 -1
- data/lib/linguify/linguified.rb +29 -44
- data/lib/linguify/reduction.rb +20 -5
- data/lib/linguify/sexp.rb +68 -3
- data/lib/linguify.rb +6 -0
- data/linguify.gemspec +2 -2
- data/spec/linguify/linguify_spec.rb +53 -1
- metadata +3 -3
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
|
+
0.5.2
|
data/lib/linguify/linguified.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
|
@@ -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
|
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 /^{
|
55
|
+
break if /^{:[0-9]*}$/ =~ str
|
56
56
|
end
|
57
57
|
|
58
|
-
@encoded = str
|
59
|
-
|
60
58
|
@merged_code = []
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
171
|
-
|
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
|
|
data/lib/linguify/reduction.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
|
@@ -82,7 +82,11 @@ module Linguify
|
|
82
82
|
raise "unsupported argument type #{args}"
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
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
|
-
|
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 =>
|
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
|
-
|
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
|
-
|
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
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.
|
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-
|
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
|
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.
|
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
|
+
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:
|
118
|
+
hash: 914071381584343177
|
119
119
|
segments:
|
120
120
|
- 0
|
121
121
|
version: "0"
|