expressive 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,15 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- expressive (0.0.2)
4
+ expressive (0.0.3)
5
5
  awesome_print (~> 1.0.2)
6
6
  polyglot (~> 0.3.3)
7
+ rest-client (~> 1.6.7)
7
8
  treetop (~> 1.4.10)
8
9
 
9
10
  GEM
10
11
  remote: http://rubygems.org/
11
12
  specs:
13
+ addressable (2.3.2)
12
14
  awesome_print (1.0.2)
15
+ coderay (1.0.7)
16
+ crack (0.3.1)
13
17
  diff-lcs (1.1.3)
14
18
  ffi (1.1.5)
15
19
  guard (1.3.2)
@@ -22,7 +26,13 @@ GEM
22
26
  rb-fchange (~> 0.0.5)
23
27
  rb-fsevent (~> 0.9.1)
24
28
  rb-inotify (~> 0.8.8)
29
+ method_source (0.8)
30
+ mime-types (1.19)
25
31
  polyglot (0.3.3)
32
+ pry (0.9.10)
33
+ coderay (~> 1.0.5)
34
+ method_source (~> 0.8)
35
+ slop (~> 3.3.1)
26
36
  rb-fchange (0.0.5)
27
37
  ffi
28
38
  rb-fsevent (0.9.1)
@@ -30,6 +40,8 @@ GEM
30
40
  ffi (>= 0.5.0)
31
41
  rdoc (3.12)
32
42
  json (~> 1.4)
43
+ rest-client (1.6.7)
44
+ mime-types (>= 1.16)
33
45
  rspec (2.11.0)
34
46
  rspec-core (~> 2.11.0)
35
47
  rspec-expectations (~> 2.11.0)
@@ -39,10 +51,14 @@ GEM
39
51
  diff-lcs (~> 1.1.3)
40
52
  rspec-mocks (2.11.2)
41
53
  ruby_gntp (0.3.4)
54
+ slop (3.3.2)
42
55
  thor (0.16.0)
43
- treetop (1.4.10)
56
+ treetop (1.4.11)
44
57
  polyglot
45
58
  polyglot (>= 0.3.1)
59
+ webmock (1.8.11)
60
+ addressable (>= 2.2.7)
61
+ crack (>= 0.1.7)
46
62
 
47
63
  PLATFORMS
48
64
  ruby
@@ -52,6 +68,8 @@ DEPENDENCIES
52
68
  expressive!
53
69
  guard (~> 1.3.2)
54
70
  guard-rspec (~> 1.2.1)
71
+ pry (~> 0.9.10)
55
72
  rdoc (~> 3.12)
56
73
  rspec (~> 2.11.0)
57
74
  ruby_gntp (~> 0.3.4)
75
+ webmock (~> 1.8.11)
data/Guardfile CHANGED
@@ -1,30 +1,9 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- guard 'bundler' do
5
- watch('Gemfile')
6
- # Uncomment next line if Gemfile contain `gemspec' command
7
- # watch(/^.+\.gemspec/)
8
- end
9
-
10
- guard 'rspec', :cli => "--color --format nested --fail-fast", :version => 2 do
4
+ guard 'rspec', :cli => "--color --format nested --fail-fast", :version => 2, :notification => false do
11
5
  watch(%r{^spec/.+_spec\.rb$})
12
6
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
13
- watch('spec/spec_helper.rb') { "spec" }
14
-
15
- # Rails example
16
- watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
17
- watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
18
- watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
19
- watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
- watch('config/routes.rb') { "spec/routing" }
21
- watch('app/controllers/application_controller.rb') { "spec/controllers" }
22
-
23
- # Capybara request specs
24
- watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
25
-
26
- # Turnip features and steps
27
- watch(%r{^spec/acceptance/(.+)\.feature$})
28
- watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
7
+ watch('spec/spec_helper.rb') { "rspec" }
29
8
  end
30
9
 
data/expressive.gemspec CHANGED
@@ -22,8 +22,11 @@ Gem::Specification.new do |gem|
22
22
  gem.add_development_dependency "bundler", "~> 1.1.4"
23
23
  gem.add_development_dependency "guard", "~> 1.3.2"
24
24
  gem.add_development_dependency "guard-rspec", "~> 1.2.1"
25
+ gem.add_development_dependency "webmock", "~> 1.8.11"
26
+ gem.add_development_dependency "pry", "~> 0.9.10"
25
27
 
26
28
  gem.add_dependency "polyglot", "~> 0.3.3"
27
29
  gem.add_dependency "treetop", "~> 1.4.10"
28
30
  gem.add_dependency "awesome_print", "~> 1.0.2"
31
+ gem.add_dependency "rest-client", "~> 1.6.7"
29
32
  end
@@ -1,3 +1,3 @@
1
1
  module Expressive
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/expressive.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'polyglot'
2
2
  require 'treetop'
3
3
  require 'awesome_print'
4
+ require 'rest_client'
4
5
  require File.join(File.dirname(__FILE__), 'scope')
5
6
 
6
7
  Treetop.load File.join(File.dirname(__FILE__), 'expressive_grammar.treetop')
@@ -15,30 +16,39 @@ module Expressive
15
16
  @parser ||= ::ExpressiveParser.new
16
17
  @parser.parse(expressions)
17
18
  end
18
- end
19
19
 
20
+ def self.all_symbols
21
+ %w(+ - * / = set sum post >= > < <= and or if)
22
+ end
23
+ end
20
24
 
21
- module Boolean
25
+ module Boolean
22
26
  def eval(scope)
23
- 'true' == text_value
27
+ 'true' == text_value
24
28
  end
25
29
  end
26
30
 
27
- module IntegerValue
28
- def eval(scope)
31
+ module IntegerValue
32
+ def eval(scope)
29
33
  text_value.to_i
30
34
  end
31
35
  end
32
36
 
33
- module FloatValue
34
- def eval(scope)
35
- text_value.to_f
37
+ module FloatValue
38
+ def eval(scope)
39
+ text_value.to_f
40
+ end
41
+ end
42
+
43
+ module StringValue
44
+ def eval(scope)
45
+ text_value.gsub('"', '')
36
46
  end
37
47
  end
38
48
 
39
49
  class Program < Treetop::Runtime::SyntaxNode
40
50
  def eval(scope)
41
- elements.map {|e|
51
+ elements.map {|e|
42
52
  e.eval(scope)
43
53
  }.last
44
54
  end
@@ -83,7 +93,7 @@ class Function
83
93
  end
84
94
 
85
95
  def call(scope, statements)
86
- parameters = statements.map {|c| c.eval(scope)}
96
+ parameters = statements.map {|c| c.eval(scope)}
87
97
  @block.call(*parameters)
88
98
  end
89
99
  end
@@ -17,13 +17,17 @@ grammar Expressive
17
17
  end
18
18
 
19
19
  rule value
20
- (boolean / number)
20
+ (string / boolean / number)
21
21
  end
22
22
 
23
23
  rule word
24
24
  [a-zA-Z]+
25
25
  end
26
26
 
27
+ rule string
28
+ '"' ([^"\\] / "\\" . )* '"' <StringValue>
29
+ end
30
+
27
31
  rule number
28
32
  ( float / integer )
29
33
  end
data/lib/scope.rb CHANGED
@@ -25,14 +25,13 @@ class Scope
25
25
  @symbols
26
26
  end
27
27
 
28
- def define(name, &block)
29
- self[name] = Function.new(&block)
28
+ def define(name, &block)
29
+ self[name] = Function.new(&block)
30
30
  end
31
31
 
32
- def syntax(name, &block)
33
- self[name] = Syntax.new(&block)
32
+ def syntax(name, &block)
33
+ self[name] = Syntax.new(&block)
34
34
  end
35
-
36
35
  end
37
36
 
38
37
  class TopLevel < Scope
@@ -43,11 +42,33 @@ class TopLevel < Scope
43
42
  scope[cells.first.text_value] = cells[1].eval(scope)
44
43
  end
45
44
 
45
+ syntax('post') do |scope, cells|
46
+ uri = cells.shift.text_value.gsub('"', '')
47
+ payload = {}
48
+ cells.each do |key|
49
+ payload[key.text_value] = scope[key.text_value]
50
+ end
51
+ begin
52
+ response = RestClient.post uri, payload
53
+ scope = scope.merge(response) if response.is_a?(Hash)
54
+ rescue RestClient::Exception => e
55
+ scope['_errors'] = e.message
56
+ end
57
+ scope
58
+ end
59
+
46
60
  define('+') {|a,b| a.to_f + b.to_f }
47
61
  define('-') {|a,b| a.to_f - b.to_f }
48
62
  define('*') {|a,b| a.to_f * b.to_f }
49
63
  define('/') {|a,b| a.to_f / b.to_f }
50
64
  define('=') {|a,b| a == b }
51
- define('sum') {|*args| args.flatten.map(&:to_f).reduce(:+) }
65
+ define('>') {|a,b| a.to_f > b.to_f }
66
+ define('<') {|a,b| a.to_f < b.to_f }
67
+ define('>=') {|a,b| a.to_f >= b.to_f }
68
+ define('<=') {|a,b| a.to_f <= b.to_f }
69
+ define('and') {|a,b| !!a && !!b }
70
+ define('or') {|a,b| !!a || !!b }
71
+ define('sum') { |*args| args.flatten.map(&:to_f).reduce(:+) }
72
+ define('if') { |*args| args.compact!; args[0] ? args[1] : args[2] }
52
73
  end
53
74
  end
@@ -4,7 +4,11 @@ describe "Expressive" do
4
4
  before(:each) do
5
5
  @scope = TopLevel.new
6
6
  end
7
-
7
+
8
+ describe "all_symbols" do
9
+ it { Expressive.all_symbols.should =~ %w(+ - * / = set sum post >= > < <= and or if) }
10
+ end
11
+
8
12
  describe "understands booleans" do
9
13
  it { Expressive.run("true").should eql true }
10
14
  it { Expressive.run("false").should eql false }
@@ -12,7 +16,14 @@ describe "Expressive" do
12
16
 
13
17
  describe "understands numbers" do
14
18
  it { Expressive.run("5").should eql 5 }
15
- it { Expressive.run("5.5").should eql 5.5 }
19
+ it { Expressive.run("5.5").should eql 5.5 }
20
+ end
21
+
22
+ describe "understands string literals" do
23
+ it { Expressive.run('"hello world "').should eql "hello world " }
24
+ it { Expressive.run('"hello world 2012"').should eql "hello world 2012" }
25
+ it { Expressive.run('"hello world 2.5"').should eql "hello world 2.5" }
26
+ it { Expressive.run('"hello world false"').should eql "hello world false" }
16
27
  end
17
28
 
18
29
  it "understands variables" do
@@ -20,16 +31,113 @@ describe "Expressive" do
20
31
  Expressive.run("hello", @scope).should eql "World"
21
32
  end
22
33
 
23
- describe "understands arithmetic" do
34
+ describe "under stands arithmetic" do
24
35
  it { Expressive.run("(+ 4 2)").should eql 6.0 }
25
36
  it { Expressive.run("(- 4 2)").should eql 2.0 }
26
37
  it { Expressive.run("(* 4 2)").should eql 8.0 }
27
38
  it { Expressive.run("(/ 4 2)").should eql 2.0 }
28
- it { Expressive.run("(sum 1 2 3)").should eql 6.0}
39
+ it { Expressive.run("(sum 1 2 3)").should eql 6.0 }
40
+ end
41
+
42
+ describe "understands comparisson" do
43
+ it { Expressive.run("(= 4 2)").should eql false }
44
+ it { Expressive.run("(= 4 4)").should eql true }
45
+ it { Expressive.run("(> 4 2)").should eql true }
46
+ it { Expressive.run("(> 2 4)").should eql false }
47
+ it { Expressive.run("(< 4 2)").should eql false }
48
+ it { Expressive.run("(< 2 4)").should eql true }
49
+ it { Expressive.run("(>= 4 4)").should eql true }
50
+ it { Expressive.run("(<= 4 4)").should eql true }
29
51
  end
30
52
 
31
53
  describe "understands compound statements" do
32
54
  it { Expressive.run("(= (+ 4 2) 6)").should eql true }
55
+ it { Expressive.run("(if (and (< 3 9) (> 2 1)), true, false)").should eql true }
56
+ it { Expressive.run("(if (and (< 10 9) (> 2 1)), true, false)").should eql false }
57
+ end
58
+
59
+ describe "understands conditional statements" do
60
+ it { Expressive.run('(if (> 5 4) "greater" "not so greater")').should eql "greater" }
61
+
62
+ context "it understands the need for commas (if you like that kind of thing" do
63
+ it { Expressive.run('(if (< 5 4), "greater", "not so greater")').should eql "not so greater" }
64
+ end
65
+
66
+ context "nil values" do
67
+ it { Expressive.run('(if (> nil_value 4) "greater" "not so greater")', @scope).should eql "not so greater" }
68
+ it { Expressive.run('(if (> 4 nil_value) "greater" "not so greater")', @scope).should eql "greater" }
69
+ it { Expressive.run('(if (> 4 nil_value) "greater" "not so greater")', @scope).should eql "greater" }
70
+ it { Expressive.run('(if (<= nil_value 4) "greater" "not so greater")', @scope).should eql "greater" }
71
+ it { Expressive.run('(if (>= 4 nil_value) "greater" "not so greater")', @scope).should eql "greater" }
72
+ end
73
+ end
74
+
75
+ describe "understands logical statements" do
76
+ it { Expressive.run('(and true true)').should eql true }
77
+ it { Expressive.run('(and true false)').should eql false }
78
+ it { Expressive.run('(or true true)').should eql true }
79
+ it { Expressive.run('(or true false)').should eql true }
80
+ it { Expressive.run('(or false false)').should eql false }
81
+
82
+ context "nil values" do
83
+ it { Expressive.run('(and true nil_value)', @scope).should eql false }
84
+ it { Expressive.run('(and nil_value true)', @scope).should eql false }
85
+ it { Expressive.run('(or nil_value true)', @scope).should eql true }
86
+ it { Expressive.run('(or nil_value false)', @scope).should eql false }
87
+ end
88
+ end
89
+
90
+ describe "understands web-hook statements" do
91
+ context "with a valid response" do
92
+ it "should post to the given uri" do
93
+ request = stub_request(:post, "www.example.com")
94
+ Expressive.run('(post "http://www.example.com")')
95
+ assert_requested(request)
96
+ end
97
+
98
+ it "should post the cope parameters if given" do
99
+ @scope['ohai'] = "world"
100
+ request = stub_request(:post, "www.example.com").with(body: {'ohai' => 'world'})
101
+ Expressive.run('(post "http://www.example.com" ohai)', @scope)
102
+ assert_requested(request)
103
+ end
104
+
105
+ it "should update the scope based on the response" do
106
+ @scope['ohai'] = "world"
107
+ request = stub_request(:post, "www.example.com").with(body: {'ohai' => 'world'}).to_return(body: {'goodbye' => 'srsly'})
108
+ Expressive.run('(post "http://www.example.com" ohai)', @scope)
109
+ @scope['goodbye'].should eql 'srsly'
110
+ end
111
+ end
112
+
113
+ context "when the response is invalid" do
114
+ context "sets error custom message" do
115
+ it "should add an entry in the errors element of the scope" do
116
+ message = 'Something went Pete Tong'
117
+ exception = RestClient::Exception.new
118
+ exception.message = message
119
+ stub_request(:post, 'www.example.com').to_raise(exception)
120
+ Expressive.run('(post "http://www.example.com")', @scope)
121
+ @scope['_errors'].should eql message
122
+ end
123
+ end
124
+
125
+ context "bad uri" do
126
+ it "should add an entry in the errors element of the scope" do
127
+ stub_request(:post, "badexample.com").to_raise(RestClient::ResourceNotFound.new)
128
+ Expressive.run('(post "badexample.com")', @scope)
129
+ @scope['_errors'].should eql 'Resource Not Found'
130
+ end
131
+ end
132
+
133
+ context "timeout" do
134
+ it "should add an entry in the errors element of the scope" do
135
+ stub_request(:post, 'www.example.com').to_timeout
136
+ Expressive.run('(post "http://www.example.com")', @scope)
137
+ @scope['_errors'].should eql 'Request Timeout'
138
+ end
139
+ end
140
+ end
33
141
  end
34
142
 
35
143
  context "looking up an id based on a value" do
data/spec/spec_helper.rb CHANGED
@@ -8,7 +8,10 @@ rescue Bundler::BundlerError => e
8
8
  exit e.status_code
9
9
  end
10
10
  require 'rspec'
11
+ require 'webmock/rspec'
12
+ require 'pry'
11
13
 
12
14
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
15
  $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+
14
17
  require 'expressive'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-10 00:00:00.000000000 Z
12
+ date: 2012-10-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby_gntp
@@ -107,6 +107,38 @@ dependencies:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
109
  version: 1.2.1
110
+ - !ruby/object:Gem::Dependency
111
+ name: webmock
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 1.8.11
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 1.8.11
126
+ - !ruby/object:Gem::Dependency
127
+ name: pry
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 0.9.10
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: 0.9.10
110
142
  - !ruby/object:Gem::Dependency
111
143
  name: polyglot
112
144
  requirement: !ruby/object:Gem::Requirement
@@ -155,6 +187,22 @@ dependencies:
155
187
  - - ~>
156
188
  - !ruby/object:Gem::Version
157
189
  version: 1.0.2
190
+ - !ruby/object:Gem::Dependency
191
+ name: rest-client
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ~>
196
+ - !ruby/object:Gem::Version
197
+ version: 1.6.7
198
+ type: :runtime
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ~>
204
+ - !ruby/object:Gem::Version
205
+ version: 1.6.7
158
206
  description: Scheme-like language for manipulating CaseBlocks cases
159
207
  email:
160
208
  - ijonas@emergeadapt.com
@@ -193,7 +241,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
193
241
  version: '0'
194
242
  segments:
195
243
  - 0
196
- hash: -3233629507963509909
244
+ hash: -977329044772272752
197
245
  required_rubygems_version: !ruby/object:Gem::Requirement
198
246
  none: false
199
247
  requirements:
@@ -202,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
250
  version: '0'
203
251
  segments:
204
252
  - 0
205
- hash: -3233629507963509909
253
+ hash: -977329044772272752
206
254
  requirements: []
207
255
  rubyforge_project:
208
256
  rubygems_version: 1.8.23