alf-sequel 0.13.0

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.
Files changed (63) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/Gemfile +19 -0
  3. data/Gemfile.lock +38 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +12 -0
  6. data/README.md +11 -0
  7. data/Rakefile +11 -0
  8. data/lib/alf/sequel/adapter.rb +57 -0
  9. data/lib/alf/sequel/cog.rb +92 -0
  10. data/lib/alf/sequel/compiler/predicate.rb +76 -0
  11. data/lib/alf/sequel/compiler.rb +168 -0
  12. data/lib/alf/sequel/connection/connection_methods.rb +46 -0
  13. data/lib/alf/sequel/connection/schema_methods.rb +76 -0
  14. data/lib/alf/sequel/connection/update_methods.rb +63 -0
  15. data/lib/alf/sequel/connection.rb +23 -0
  16. data/lib/alf/sequel/loader.rb +2 -0
  17. data/lib/alf/sequel/unit_of_work/atomic.rb +35 -0
  18. data/lib/alf/sequel/unit_of_work/delete.rb +24 -0
  19. data/lib/alf/sequel/unit_of_work/insert.rb +60 -0
  20. data/lib/alf/sequel/unit_of_work/update.rb +60 -0
  21. data/lib/alf/sequel/unit_of_work.rb +11 -0
  22. data/lib/alf/sequel/version.rb +16 -0
  23. data/lib/alf/sequel.rb +7 -0
  24. data/lib/alf-sequel.rb +1 -0
  25. data/spec/adapter/test_recognize.rb +50 -0
  26. data/spec/alf.db +0 -0
  27. data/spec/compiler/test_clip.rb +40 -0
  28. data/spec/compiler/test_compact.rb +18 -0
  29. data/spec/compiler/test_extend.rb +16 -0
  30. data/spec/compiler/test_intersect.rb +18 -0
  31. data/spec/compiler/test_join.rb +18 -0
  32. data/spec/compiler/test_leaf_operand.rb +24 -0
  33. data/spec/compiler/test_matching.rb +34 -0
  34. data/spec/compiler/test_not_matching.rb +34 -0
  35. data/spec/compiler/test_predicate.rb +141 -0
  36. data/spec/compiler/test_project.rb +64 -0
  37. data/spec/compiler/test_rename.rb +26 -0
  38. data/spec/compiler/test_restrict.rb +48 -0
  39. data/spec/compiler/test_sort.rb +18 -0
  40. data/spec/compiler/test_union.rb +18 -0
  41. data/spec/compiler_helper.rb +34 -0
  42. data/spec/connection/test_connection_uri.rb +54 -0
  43. data/spec/connection/test_delete.rb +20 -0
  44. data/spec/connection/test_heading.rb +16 -0
  45. data/spec/connection/test_insert.rb +24 -0
  46. data/spec/connection/test_keys.rb +24 -0
  47. data/spec/connection/test_lock.rb +15 -0
  48. data/spec/connection/test_ping.rb +26 -0
  49. data/spec/connection/test_relvar.rb +16 -0
  50. data/spec/connection/test_update.rb +20 -0
  51. data/spec/fixtures/sap.db +0 -0
  52. data/spec/fixtures/sap.rb +43 -0
  53. data/spec/spec_helper.rb +35 -0
  54. data/spec/test_assumptions.rb +14 -0
  55. data/spec/test_sequel.rb +10 -0
  56. data/spec/unit_of_work/atomic/test_run.rb +72 -0
  57. data/spec/unit_of_work/delete/test_delete.rb +39 -0
  58. data/spec/unit_of_work/insert/test_run.rb +71 -0
  59. data/spec/unit_of_work/update/test_run.rb +39 -0
  60. data/tasks/fixtures.rake +12 -0
  61. data/tasks/gem.rake +8 -0
  62. data/tasks/test.rake +6 -0
  63. metadata +174 -0
@@ -0,0 +1,23 @@
1
+ module Alf
2
+ module Sequel
3
+ #
4
+ # Specialization of Alf::Connection to distribute Sequel datasets
5
+ #
6
+ class Connection < Alf::Adapter::Connection
7
+
8
+ def compiler
9
+ Compiler.new
10
+ end
11
+
12
+ require_relative 'connection/schema_methods'
13
+ require_relative 'connection/connection_methods'
14
+ require_relative 'connection/update_methods'
15
+ include SchemaMethods
16
+ include ConnectionMethods
17
+ include UpdateMethods
18
+
19
+ alias_method :to_s, :connection_uri
20
+
21
+ end # class Connection
22
+ end # module Sequel
23
+ end # module Alf
@@ -0,0 +1,2 @@
1
+ require "alf-core"
2
+ require "sequel"
@@ -0,0 +1,35 @@
1
+ module Alf
2
+ module Sequel
3
+ module UnitOfWork
4
+ module Atomic
5
+
6
+ def initialize(connection)
7
+ @connection = connection
8
+ @ran = false
9
+ @failure = nil
10
+ end
11
+ attr_reader :connection, :failure
12
+
13
+ def ran?
14
+ @ran
15
+ end
16
+
17
+ def failed?
18
+ not(@failure.nil?)
19
+ end
20
+
21
+ def run
22
+ raise IllegalStateError, "Unit of work already ran" if ran?
23
+ _run
24
+ self
25
+ rescue => ex
26
+ @failure = ex
27
+ raise
28
+ ensure
29
+ @ran = true
30
+ end
31
+
32
+ end # module Atomic
33
+ end # module UnitOfWork
34
+ end # module Sequel
35
+ end # module Alf
@@ -0,0 +1,24 @@
1
+ module Alf
2
+ module Sequel
3
+ module UnitOfWork
4
+ class Delete
5
+ include UnitOfWork::Atomic
6
+
7
+ def initialize(connection, relvar_name, predicate)
8
+ super(connection)
9
+ @relvar_name = relvar_name
10
+ @predicate = predicate
11
+ end
12
+
13
+ private
14
+
15
+ def _run
16
+ connection.with_dataset(@relvar_name, @predicate) do |d|
17
+ d.delete
18
+ end
19
+ end
20
+
21
+ end # class Delete
22
+ end # module UnitOfWork
23
+ end # module Sequel
24
+ end # module Alf
@@ -0,0 +1,60 @@
1
+ module Alf
2
+ module Sequel
3
+ module UnitOfWork
4
+ class Insert
5
+ include UnitOfWork::Atomic
6
+
7
+ def initialize(connection, relvar_name, inserted)
8
+ super(connection)
9
+ @relvar_name = relvar_name
10
+ @inserted = inserted
11
+ @insert_result = nil
12
+ end
13
+
14
+ def matching_relation
15
+ @matching_relation ||= begin
16
+ raise IllegalStateError, "Unit of work not ran" unless ran?
17
+ unless @insert_result
18
+ raise UnsupportedError, "Composite keys insertion feedback is unsupported."
19
+ end
20
+ Relation(@insert_result)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def candidate_keys
27
+ @candidate_keys ||= connection.keys(@relvar_name)
28
+ end
29
+
30
+ def primary_key
31
+ candidate_keys.first
32
+ end
33
+
34
+ def best_candidate_key
35
+ best = candidate_keys.to_a.find{|k| k.size == 1}
36
+ best || candidate_keys.first
37
+ end
38
+
39
+ def _run
40
+ connection.with_dataset(@relvar_name) do |d|
41
+ bk = best_candidate_key
42
+ if bk and bk.size == 1
43
+ pk_field_name = bk.to_a.first
44
+ supported = d.supports_returning?(:insert)
45
+ d = d.returning(pk_field_name) if supported
46
+ @insert_result = @inserted.map{|t|
47
+ res = d.insert(t.to_hash)
48
+ supported ? res.first : { pk_field_name => res }
49
+ }
50
+ else
51
+ @inserted.each{|t| d.insert(t.to_hash) }
52
+ @insert_result = nil
53
+ end
54
+ end
55
+ end
56
+
57
+ end # class Insert
58
+ end # module UnitOfWork
59
+ end # module Sequel
60
+ end # module Alf
@@ -0,0 +1,60 @@
1
+ module Alf
2
+ module Sequel
3
+ module UnitOfWork
4
+ class Update
5
+ include UnitOfWork::Atomic
6
+
7
+ def initialize(connection, relvar_name, updating, predicate)
8
+ super(connection)
9
+ @relvar_name = relvar_name
10
+ @updating = updating
11
+ @predicate = predicate
12
+ end
13
+
14
+ def matching_relation
15
+ raise IllegalStateError, "Unit of work not ran" unless ran?
16
+
17
+ # Check that updating is understandable
18
+ unless TupleLike===@updating
19
+ raise UnsupportedError, "Non-tuple update feedback is unsupported."
20
+ end
21
+ updating = @updating.to_hash
22
+ updating_keys = updating.keys
23
+
24
+ # extract all keys, and pk in particular
25
+ keys = connection.keys(@relvar_name)
26
+ pk = keys.first
27
+
28
+ # Strategy 1), @updating contains a key
29
+ if key = keys.to_a.find{|k| !(k & updating_keys).empty? }
30
+ return Relation(@updating.project(key).to_hash)
31
+ end
32
+
33
+ raise UnsupportedError, "Unable to extract update matching relation"
34
+ end
35
+
36
+ def pk_matching_relation
37
+ mr, pkey = matching_relation, connection.keys(@relvar_name).first
38
+ if mr.to_attr_list == pkey.to_attr_list
39
+ mr
40
+ else
41
+ filter = mr.tuple_extract.to_hash
42
+ tuples = connection.cog(@relvar_name)
43
+ .filter(filter)
44
+ .select(pkey.to_a)
45
+ Relation(tuples)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def _run
52
+ connection.with_dataset(@relvar_name, @predicate) do |d|
53
+ d.update Tuple(@updating).to_hash
54
+ end
55
+ end
56
+
57
+ end # class Update
58
+ end # module UnitOfWork
59
+ end # module Sequel
60
+ end # module Alf
@@ -0,0 +1,11 @@
1
+ module Alf
2
+ module Sequel
3
+ module UnitOfWork
4
+
5
+ end # module UnitOfWork
6
+ end # module Sequel
7
+ end # module Alf
8
+ require_relative 'unit_of_work/atomic'
9
+ require_relative 'unit_of_work/insert'
10
+ require_relative 'unit_of_work/delete'
11
+ require_relative 'unit_of_work/update'
@@ -0,0 +1,16 @@
1
+ module Alf
2
+ module Sequel
3
+ module Version
4
+
5
+ MAJOR = 0
6
+ MINOR = 13
7
+ TINY = 0
8
+
9
+ def self.to_s
10
+ [ MAJOR, MINOR, TINY ].join('.')
11
+ end
12
+
13
+ end
14
+ VERSION = Version.to_s
15
+ end
16
+ end
data/lib/alf/sequel.rb ADDED
@@ -0,0 +1,7 @@
1
+ require_relative 'sequel/version'
2
+ require_relative 'sequel/loader'
3
+ require_relative 'sequel/adapter'
4
+ require_relative 'sequel/connection'
5
+ require_relative 'sequel/compiler'
6
+ require_relative 'sequel/cog'
7
+ require_relative 'sequel/unit_of_work'
data/lib/alf-sequel.rb ADDED
@@ -0,0 +1 @@
1
+ require_relative "alf/sequel"
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Adapter, "recognizes?" do
5
+
6
+ it "recognizes ::Sequel::Database objects" do
7
+ begin
8
+ db = ::Sequel.connect(sequel_database_memory)
9
+ Adapter.recognizes?(db).should be_true
10
+ ensure
11
+ db.disconnect if db
12
+ end
13
+ end
14
+
15
+ it "recognizes sqlite files" do
16
+ Adapter.recognizes?("#{sequel_database_path}").should be_true
17
+ end
18
+
19
+ it "recognizes in memory sqlite databases" do
20
+ Adapter.recognizes?(sequel_database_memory).should be_true
21
+ end
22
+
23
+ it "recognizes a Path to a sqlite databases" do
24
+ Adapter.recognizes?(sequel_database_path).should be_true
25
+ Adapter.recognizes?("nosuchone.db").should be_true
26
+ end
27
+
28
+ it "recognizes database uris" do
29
+ Adapter.recognizes?("postgres://localhost/database").should be_true
30
+ Adapter.recognizes?(sequel_database_uri).should be_true
31
+ end
32
+
33
+ it "recognizes a Hash ala Rails" do
34
+ config = {"adapter" => "sqlite", "database" => "#{sequel_database_path}"}
35
+ Adapter.recognizes?(config).should be_true
36
+ Adapter.recognizes?(Tools.symbolize_keys(config)).should be_true
37
+ end
38
+
39
+ it "should not be too permissive" do
40
+ Adapter.recognizes?(nil).should be_false
41
+ end
42
+
43
+ it "should let Adapter autodetect sqlite files" do
44
+ Alf::Adapter.autodetect(sequel_database_path).should be(Adapter)
45
+ Alf::Adapter.autodetect("#{sequel_database_path}").should be(Adapter)
46
+ end
47
+
48
+ end
49
+ end
50
+ end
data/spec/alf.db ADDED
Binary file
@@ -0,0 +1,40 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "clip" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'when the operand is fully compilable' do
9
+ let(:expr){ clip(suppliers, [:sid, :name]) }
10
+
11
+ specify{
12
+ subject.sql.should eq("SELECT `t1`.`sid`, `t1`.`name` FROM `suppliers` AS 't1'")
13
+ }
14
+ end
15
+
16
+ context 'when the operand is fully compilable (distinct normally needed)' do
17
+ let(:expr){ clip(suppliers, [:city]) }
18
+
19
+ specify{
20
+ subject.sql.should eq("SELECT `t1`.`city` FROM `suppliers` AS 't1'")
21
+ }
22
+ end
23
+
24
+ context 'when the operand is fully compilable (allbut, distinct)' do
25
+ let(:expr){ clip(suppliers, [:sid, :name, :status], :allbut => true) }
26
+
27
+ specify{
28
+ subject.sql.should eq("SELECT `t1`.`city` FROM `suppliers` AS 't1'")
29
+ }
30
+ end
31
+
32
+ context 'when the operand is not compilable' do
33
+ let(:expr){ clip(an_operand, [:sid, :name]) }
34
+
35
+ it{ should be_a(Engine::Cog) }
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "compact" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'when the operand is fully compilable' do
9
+ let(:expr){ compact(suppliers) }
10
+
11
+ specify{
12
+ subject.sql.should eq("SELECT DISTINCT * FROM `suppliers` AS 't1'")
13
+ }
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "extend" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'with a native predicate' do
9
+ let(:expr){ extend(suppliers, :big => lambda{}) }
10
+
11
+ it{ should be_a(Engine::SetAttr) }
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "intersect" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'when the operand is fully compilable' do
9
+ let(:expr){ intersect(suppliers, supplies) }
10
+
11
+ specify do
12
+ subject.sql.should eq("SELECT * FROM (SELECT * FROM `suppliers` AS 't1' INTERSECT SELECT * FROM `supplies` AS 't2') AS 't3'")
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "join" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'when the operand is fully compilable' do
9
+ let(:expr){ join(suppliers, supplies) }
10
+
11
+ specify do
12
+ subject.sql.should eq("SELECT * FROM (SELECT * FROM `suppliers` AS 't1' INNER JOIN (SELECT * FROM `supplies` AS 't2') AS 't3' USING (`sid`)) AS 't3'")
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "leaf_operand" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'on the proper context' do
9
+ let(:expr){ suppliers }
10
+
11
+ it{ should be_a(Cog) }
12
+ end
13
+
14
+ context 'on another context' do
15
+ let(:expr){ Algebra.named_operand(:suppliers, self) }
16
+
17
+ pending "support for multiple context is needed" do
18
+ it{ should_not be_a(Cog) }
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "matching" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'when no common attributes' do
9
+ let(:expr){ matching(suppliers, project(supplies, [:part_id])) }
10
+
11
+ specify do
12
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (EXISTS (SELECT `t2`.`part_id` FROM `supplies` AS 't2'))")
13
+ end
14
+ end
15
+
16
+ context 'when only one common attributes' do
17
+ let(:expr){ matching(suppliers, supplies) }
18
+
19
+ specify do
20
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (`t1`.`sid` IN (SELECT `t2`.`sid` FROM `supplies` AS 't2'))")
21
+ end
22
+ end
23
+
24
+ context 'when many common attributes' do
25
+ let(:expr){ matching(suppliers, parts) }
26
+
27
+ specify do
28
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (EXISTS (SELECT * FROM `parts` AS 't2' WHERE ((`t1`.`name` = `t2`.`name`) AND (`t1`.`city` = `t2`.`city`))))")
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "not_matching" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ context 'when no common attributes' do
9
+ let(:expr){ not_matching(suppliers, project(supplies, [:part_id])) }
10
+
11
+ specify do
12
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE NOT (EXISTS (SELECT `t2`.`part_id` FROM `supplies` AS 't2'))")
13
+ end
14
+ end
15
+
16
+ context 'when only one common attributes' do
17
+ let(:expr){ not_matching(suppliers, supplies) }
18
+
19
+ specify do
20
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (`t1`.`sid` NOT IN (SELECT `t2`.`sid` FROM `supplies` AS 't2'))")
21
+ end
22
+ end
23
+
24
+ context 'when many common attributes' do
25
+ let(:expr){ not_matching(suppliers, parts) }
26
+
27
+ specify do
28
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE NOT (EXISTS (SELECT * FROM `parts` AS 't2' WHERE ((`t1`.`name` = `t2`.`name`) AND (`t1`.`city` = `t2`.`city`))))")
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,141 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ class Compiler
5
+ describe Predicate do
6
+
7
+ let(:p) { Alf::Predicate }
8
+ let(:compiler) { Predicate.new }
9
+ let(:dataset) { sap.cog(:suppliers).dataset }
10
+ let(:compiled) { compiler.call(expr) }
11
+
12
+ subject{ dataset.literal(compiled) }
13
+
14
+ context 'tautology' do
15
+ let(:expr){ p.tautology }
16
+
17
+ it{ should eq("(1 = 1)") }
18
+ end
19
+
20
+ context 'contradiction' do
21
+ let(:expr){ p.contradiction }
22
+
23
+ it{ should eq("(1 = 0)") }
24
+ end
25
+
26
+ context 'var_ref' do
27
+ let(:expr){ p.var_ref(:x) }
28
+
29
+ it{ should eq("`x`") }
30
+ end
31
+
32
+ context 'literal' do
33
+ let(:expr){ p.literal(12) }
34
+
35
+ it{ should eq("12") }
36
+ end
37
+
38
+ context 'eq(var, literal)' do
39
+ let(:expr){ p.eq(:x, 12) }
40
+
41
+ it{ should eq("(`x` = 12)") }
42
+ end
43
+
44
+ context 'neq(var, literal)' do
45
+ let(:expr){ p.neq(:x, 12) }
46
+
47
+ it{ should eq("(`x` != 12)") }
48
+ end
49
+
50
+ context 'eq(var, nil)' do
51
+ let(:expr){ p.eq(:x, nil) }
52
+
53
+ it{ should eq("(`x` IS NULL)") }
54
+ end
55
+
56
+ context 'eq(var, var)' do
57
+ let(:expr){ p.eq(:x, :y) }
58
+
59
+ it{ should eq("(`x` = `y`)") }
60
+ end
61
+
62
+ context 'lt(var, literal)' do
63
+ let(:expr){ p.lt(:x, 2) }
64
+
65
+ it{ should eq("(`x` < 2)") }
66
+ end
67
+
68
+ context 'lte(var, literal)' do
69
+ let(:expr){ p.lte(:x, 2) }
70
+
71
+ it{ should eq("(`x` <= 2)") }
72
+ end
73
+
74
+ context 'gt(var, literal)' do
75
+ let(:expr){ p.gt(:x, 2) }
76
+
77
+ it{ should eq("(`x` > 2)") }
78
+ end
79
+
80
+ context 'gte(var, literal)' do
81
+ let(:expr){ p.gte(:x, 2) }
82
+
83
+ it{ should eq("(`x` >= 2)") }
84
+ end
85
+
86
+ context 'not(var)' do
87
+ let(:expr){ p.not(:x) }
88
+
89
+ it{ should eq("NOT `x`") }
90
+ end
91
+
92
+ context 'not(tautology)' do
93
+ let(:expr){ p.not(true) }
94
+
95
+ it{ should eq("(1 = 0)") }
96
+ end
97
+
98
+ context 'and' do
99
+ let(:expr){ p.eq(:x, 2) & p.eq(:y, 3) }
100
+
101
+ it{ should eq("((`x` = 2) AND (`y` = 3))") }
102
+ end
103
+
104
+ context 'or' do
105
+ let(:expr){ p.eq(:x, 2) | p.eq(:y, 3) }
106
+
107
+ it{ should eq("((`x` = 2) OR (`y` = 3))") }
108
+ end
109
+
110
+ context 'comp' do
111
+ let(:expr){ p.comp(:lt, :x => 2, :y => 3) }
112
+
113
+ it{ should eq("((`x` < 2) AND (`y` < 3))") }
114
+ end
115
+
116
+ context 'in' do
117
+ let(:expr){ p.in(:x, [2, 3]) }
118
+
119
+ it{ should eq("(`x` IN (2, 3))") }
120
+ end
121
+
122
+ context 'in with a dataset at right' do
123
+ let(:expr){ p.in(:x, dataset) }
124
+
125
+ it{ should eq("(`x` IN (SELECT * FROM `suppliers`))") }
126
+ end
127
+
128
+ context 'native' do
129
+ let(:expr){ p.native(lambda{}) }
130
+
131
+ specify{
132
+ lambda{
133
+ subject
134
+ }.should throw_symbol(:pass)
135
+ }
136
+ end
137
+
138
+ end
139
+ end
140
+ end
141
+ end