neo4j-core 0.0.15-java → 2.0.0.alpha.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/Gemfile +2 -2
  2. data/README.rdoc +12 -192
  3. data/lib/neo4j-core.rb +3 -19
  4. data/lib/neo4j-core/database.rb +5 -4
  5. data/lib/neo4j-core/event_handler.rb +1 -1
  6. data/lib/neo4j-core/index/class_methods.rb +41 -27
  7. data/lib/neo4j-core/index/index.rb +4 -3
  8. data/lib/neo4j-core/index/index_config.rb +23 -30
  9. data/lib/neo4j-core/index/indexer.rb +53 -65
  10. data/lib/neo4j-core/index/indexer_registry.rb +2 -2
  11. data/lib/neo4j-core/index/lucene_query.rb +42 -53
  12. data/lib/neo4j-core/node/class_methods.rb +4 -4
  13. data/lib/neo4j-core/node/node.rb +8 -1
  14. data/lib/neo4j-core/property/property.rb +3 -1
  15. data/lib/neo4j-core/relationship/relationship.rb +10 -8
  16. data/lib/neo4j-core/rels/rels.rb +4 -9
  17. data/lib/neo4j-core/rels/traverser.rb +27 -13
  18. data/lib/neo4j-core/traversal/prune_evaluator.rb +2 -2
  19. data/lib/neo4j-core/traversal/traverser.rb +27 -122
  20. data/lib/neo4j-core/type_converters/type_converters.rb +287 -0
  21. data/lib/neo4j-core/version.rb +1 -1
  22. data/lib/neo4j-core/version.rb~ +3 -0
  23. data/lib/neo4j/config.rb +6 -3
  24. data/lib/neo4j/neo4j.rb +22 -51
  25. data/lib/neo4j/node.rb +0 -27
  26. data/lib/neo4j/relationship.rb +0 -25
  27. data/lib/test.rb +27 -0
  28. data/neo4j-core.gemspec +2 -2
  29. metadata +11 -17
  30. data/lib/neo4j-core/cypher/cypher.rb +0 -969
  31. data/lib/neo4j-core/cypher/result_wrapper.rb +0 -48
  32. data/lib/neo4j-core/hash_with_indifferent_access.rb +0 -165
  33. data/lib/neo4j-core/index/unique_factory.rb +0 -54
  34. data/lib/neo4j-core/property/java.rb +0 -59
  35. data/lib/neo4j-core/wrapper/class_methods.rb +0 -22
  36. data/lib/neo4j-core/wrapper/wrapper.rb +0 -20
  37. data/lib/neo4j/algo.rb +0 -300
  38. data/lib/neo4j/cypher.rb +0 -180
@@ -1,5 +1,5 @@
1
1
  module Neo4j
2
2
  module Core
3
- VERSION = "0.0.15"
3
+ VERSION = "2.0.0.alpha.1"
4
4
  end
5
5
  end
@@ -0,0 +1,3 @@
1
+ module Neo4jCore
2
+
3
+ end
data/lib/neo4j/config.rb CHANGED
@@ -37,7 +37,7 @@ module Neo4j
37
37
  # @return [Hash] the default file loaded by yaml
38
38
  def defaults
39
39
  require 'yaml'
40
- @defaults ||= Neo4j::Core::HashWithIndifferentAccess.new(YAML.load_file(default_file))
40
+ @defaults ||= YAML.load_file(default_file)
41
41
  end
42
42
 
43
43
  # @return [String] the expanded path of the Config[:storage_path] property
@@ -56,7 +56,7 @@ module Neo4j
56
56
  # @yield config
57
57
  # @yieldparam [Neo4j::Config] config - this configuration class
58
58
  def use
59
- @configuration ||= Neo4j::Core::HashWithIndifferentAccess.new
59
+ @configuration ||= {}
60
60
  yield @configuration
61
61
  nil
62
62
  end
@@ -123,13 +123,16 @@ module Neo4j
123
123
  map
124
124
  end
125
125
 
126
+ private
127
+
126
128
  # @return The a new configuration using default values as a hash.
127
129
  def setup()
128
- @configuration = Neo4j::Core::HashWithIndifferentAccess.new
130
+ @configuration = {}
129
131
  @configuration.merge!(defaults)
130
132
  @configuration
131
133
  end
132
134
 
135
+
133
136
  end
134
137
  end
135
138
 
data/lib/neo4j/neo4j.rb CHANGED
@@ -5,17 +5,10 @@
5
5
  # The Neo4j modules is used to interact with an Neo4j Database instance.
6
6
  # You can for example start and stop an instance and list all the nodes that exist in the database.
7
7
  #
8
- # @example
9
- # require 'neo4j'
10
- # Neo4j::Transaction.run { Neo4j.ref_node.outgoing(:friends) << Neo4j::Node.new(:name => 'andreas')}
11
- # Neo4j.ref_node.node(:outgoing, :friends)[:name] #=> 'andreas'
12
- # Neo4j.query(Neo4j.ref_node){|ref| ref > ':friends' > :x; :x}
13
- #
14
- # ==== Notice - Starting and Stopping Neo4j
8
+ # === Starting and Stopping Neo4j
15
9
  # You don't normally need to start the Neo4j database since it will be automatically started when needed.
16
10
  # Before the database is started you should configure where the database is stored, see {Neo4j::Config]}.
17
11
  #
18
- #
19
12
  module Neo4j
20
13
 
21
14
  # @return [String] The version of the Neo4j jar files
@@ -58,10 +51,9 @@ module Neo4j
58
51
  end
59
52
 
60
53
  # Checks read only mode of the database. Only one process can have write access to the database.
61
- # It will always return false if the database is not started yet.
62
54
  # @return [true, false] if the database has started up in read only mode
63
55
  def read_only?
64
- !!(@db && @db.graph && @db.read_only?)
56
+ (@db && @db.graph && @db.read_only?)
65
57
  end
66
58
 
67
59
  # Returns a started db instance. Starts it's not running.
@@ -72,10 +64,14 @@ module Neo4j
72
64
  db
73
65
  end
74
66
 
75
- # If the database is not running it returns Neo4j::Config.storage_path otherwise it asks the database
76
- # @return [String] the current storage path of the database
67
+ # Runs all user defined migrations.
68
+ def migrate!
69
+
70
+ end
71
+
72
+ # @return [String, nil] the current storage path of a running neo4j database. If the database is not running it returns nil.
77
73
  def storage_path
78
- return Neo4j::Config.storage_path unless db.running?
74
+ return nil unless db.running?
79
75
  db.storage_path
80
76
  end
81
77
 
@@ -89,42 +85,18 @@ module Neo4j
89
85
  # Check the neo4j
90
86
  # Returns an enumerable of hash values.
91
87
  #
92
- # @example Using the Cypher DSL
93
- # q = Neo4j.query{ match node(3) <=> node(:x); ret :x}
94
- # q.first[:n] #=> the @node
95
- # q.columns.first => :n
96
- #
97
- # @example Using the Cypher DSL and one parameter (n=Neo4j.ref_node)
98
- # q = Neo4j.query(Neo4j.ref_node){|n| n <=> node(:x); :x}
99
- # q.first[:n] #=> the @node
100
- # q.columns.first => :n
101
- #
102
- # @example Using an array of nodes
103
- # # same as - two_nodes=node(Neo4j.ref_node.neo_id, node_b.neo_id), b = node(b.neo_id)
104
- # q = Neo4j.query([Neo4j.ref_node, node_b], node_c){|two_nodes, b| two_nodes <=> b; b}
88
+ # @example
105
89
  #
106
- # @example With an string
107
- # q = Neo4j._query("START n=node(42) RETURN n")
108
- # q.first(:n) #=> the @node
109
- # q.columns.first => :n
90
+ # q = Neo4j.query("START n=node({node}) RETURN n", 'node' => @node.neo_id)
91
+ # q.first['n'] #=> the @node
92
+ # q.columns.first => 'n'
110
93
  #
111
- # @see Cypher
112
- # @see http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html The Cypher Query Language Documentation
94
+ # @see {http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html The Cypher Query Language Documentation}
113
95
  # @note Returns a read-once only forward iterable.
114
- # @param params parameter for the query_dsl block
115
- # @return [Neo4j::Core::Cypher::ResultWrapper] a forward read once only Enumerable, containing hash values.
116
- def query(*params, &query_dsl)
117
- q = Cypher.new(*params, &query_dsl).to_s
118
- _query(q)
119
- end
120
-
121
- # Performs a cypher query with given string
122
- # @param [String] q the cypher query as a String
123
- # @return (see #query)
124
- def _query(q)
125
- engine = Java::OrgNeo4jCypherJavacompat::ExecutionEngine.new(db)
126
- result = engine.execute(q)
127
- Neo4j::Core::Cypher::ResultWrapper.new(result)
96
+ # @return [Enumerable] a forward read once only Enumerable, containing hash values.
97
+ def query(query, params = {})
98
+ engine = org.neo4j.cypher.javacompat.ExecutionEngine.new(db)
99
+ engine.execute(query, params)
128
100
  end
129
101
 
130
102
 
@@ -193,7 +165,7 @@ module Neo4j
193
165
 
194
166
  # Usually, a client attaches relationships to this node that leads into various parts of the node space.
195
167
  # ®return the reference node, which is a "starting point" in the node space.
196
- # @note In case the ref_node has been assigned via the threadlocal_ref_node method,
168
+ # @note In case the ref_node has been assigned via the threadlocal_ref_node method,
197
169
  # then that node will be returned instead.
198
170
  # @see the design guide at http://wiki.neo4j.org/content/Design_Guide
199
171
  def ref_node(this_db = self.started_db)
@@ -227,16 +199,15 @@ module Neo4j
227
199
  # Neo4j.management(org.neo4j.management.HighAvailability).isMaster
228
200
  #
229
201
  # @param jmx_clazz the JMX class http://api.neo4j.org/current/org/neo4j/management/package-summary.html
230
- # @param this_db default currently running instance or a newly started neo4j db instance
202
+ # @param this_db default currently runnig instance or a newly started neo4j db instance
231
203
  # @see for the jmx_clazz p
232
- # @node this
233
- def management(jmx_clazz = Java::OrgNeo4jJmx::Primitives, this_db = self.started_db)
204
+ def management(jmx_clazz = org.neo4j.jmx.Primitives, this_db = self.started_db)
234
205
  this_db.management(jmx_clazz)
235
206
  end
236
207
 
237
208
  # @return [Enumerable] all nodes in the database
238
209
  def all_nodes(this_db = self.started_db)
239
- Enumerator.new(this_db, :each_node)
210
+ Enumerable::Enumerator.new(this_db, :each_node)
240
211
  end
241
212
 
242
213
  # @return [Enumerable] all nodes in the database but not wrapped in ruby classes.
data/lib/neo4j/node.rb CHANGED
@@ -9,39 +9,14 @@ module Neo4j
9
9
  # *org.neo4j.kernel.impl.core.NodeProxy* object. This java object includes the same mixin as this class. The #class method on the java object
10
10
  # returns Neo4j::Node in order to make it feel like an ordinary Ruby object.
11
11
  #
12
- # @example Create a node with one property (see {Neo4j::Core::Node::ClassMethods})
13
- # Neo4j::Node.new(:name => 'andreas')
14
- #
15
- # @example Create a relationship (see {Neo4j::Core::Traversal})
16
- # Neo4j::Node.new.outgoing(:friends) << Neo4j::Node.new
17
- #
18
- # @example Finding relationships (see {Neo4j::Core::Rels})
19
- # node.rels(:outgoing, :friends)
20
- #
21
- # @example Lucene index (see {Neo4j::Core::Index})
22
- # Neo4j::Node.trigger_on(:typex => 'MyTypeX')
23
- # Neo4j::Node.index(:name)
24
- # a = Neo4j::Node.new(:name => 'andreas', :typex => 'MyTypeX')
25
- # # finish_tx
26
- # Neo4j::Node.find(:name => 'andreas').first.should == a
27
- #
28
12
  class Node
29
13
  extend Neo4j::Core::Node::ClassMethods
30
- extend Neo4j::Core::Wrapper::ClassMethods
31
- extend Neo4j::Core::Index::ClassMethods
32
14
 
33
15
  include Neo4j::Core::Property
34
16
  include Neo4j::Core::Rels
35
17
  include Neo4j::Core::Traversal
36
18
  include Neo4j::Core::Equal
37
19
  include Neo4j::Core::Node
38
- include Neo4j::Core::Wrapper
39
- include Neo4j::Core::Property::Java # for documentation purpose only
40
- include Neo4j::Core::Index
41
-
42
- node_indexer do
43
- index_names :exact => 'default_node_index_exact', :fulltext => 'default_node_index_fulltext'
44
- end
45
20
 
46
21
  class << self
47
22
 
@@ -54,8 +29,6 @@ module Neo4j
54
29
  include Neo4j::Core::Traversal
55
30
  include Neo4j::Core::Equal
56
31
  include Neo4j::Core::Node
57
- include Neo4j::Core::Wrapper
58
- include Neo4j::Core::Index
59
32
  end
60
33
  end
61
34
  end
@@ -29,36 +29,13 @@ module Neo4j
29
29
  #
30
30
  # node.outgoing(:friends) << other_node << yet_another_node
31
31
  #
32
- # @example lucene index
33
- # Neo4j::Relationship.trigger_on(:typey => 123)
34
- # Neo4j::Relationship.index(:name)
35
- # a = Neo4j::Relationship.new(:friends, Neo4j::Node.new, Neo4j::Node.new, :typey => 123, :name => 'kalle')
36
- # # Finish tx
37
- # Neo4j::Relationship.find(:name => 'kalle').first.should be_nil
38
- #
39
32
  # @see http://api.neo4j.org/current/org/neo4j/graphdb/Relationship.html
40
33
  #
41
34
  class Relationship
42
35
  extend Neo4j::Core::Relationship::ClassMethods
43
- extend Neo4j::Core::Wrapper::ClassMethods
44
- extend Neo4j::Core::Index::ClassMethods
45
-
46
36
  include Neo4j::Core::Property
47
37
  include Neo4j::Core::Equal
48
38
  include Neo4j::Core::Relationship
49
- include Neo4j::Core::Wrapper
50
- include Neo4j::Core::Property::Java # for documentation purpose only
51
- include Neo4j::Core::Index
52
-
53
-
54
- # (see Neo4j::Core::Relationship::ClassMethods#new)
55
- def initialize(rel_type, start_node, end_node, props={})
56
- end
57
-
58
-
59
- rel_indexer do
60
- index_names :exact => 'default_rel_index_exact', :fulltext => 'default_rel_index_fulltext'
61
- end
62
39
 
63
40
  class << self
64
41
  def extend_java_class(java_clazz) #:nodoc:
@@ -66,8 +43,6 @@ module Neo4j
66
43
  include Neo4j::Core::Property
67
44
  include Neo4j::Core::Equal
68
45
  include Neo4j::Core::Relationship
69
- include Neo4j::Core::Wrapper
70
- include Neo4j::Core::Index
71
46
  end
72
47
  end
73
48
 
data/lib/test.rb ADDED
@@ -0,0 +1,27 @@
1
+ puts "TEST"
2
+
3
+ class LazyMap
4
+ include Enumerable
5
+
6
+ def initialize(stuff, &map_block)
7
+ @stuff = stuff
8
+ @map_block = map_block
9
+ end
10
+
11
+ def each
12
+ @stuff.each{|x| yield @map_block.call(x)}
13
+ end
14
+
15
+ end
16
+
17
+ class Foo
18
+ include Enumerable
19
+
20
+ def each
21
+ (1..5).to_a.each do |x|
22
+ yield x
23
+ end
24
+ end
25
+ end
26
+ e = LazyMap.new(Foo.new, &:to_s)
27
+ puts "Max #{e.find{|x| x == "2"}}"
data/neo4j-core.gemspec CHANGED
@@ -25,7 +25,7 @@ It comes included with the Apache Lucene document database.
25
25
  s.files = Dir.glob("{bin,lib,config}/**/*") + %w(README.rdoc Gemfile neo4j-core.gemspec)
26
26
  s.has_rdoc = true
27
27
  s.extra_rdoc_files = %w( README.rdoc )
28
- s.rdoc_options = ["--quiet", "--title", "Neo4j::Core", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
28
+ s.rdoc_options = ["--quiet", "--title", "Neo4j.rb", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
29
29
 
30
- s.add_dependency("neo4j-community", ">= 1.7.0")
30
+ s.add_dependency("neo4j-community", "1.6.1.alpha.1")
31
31
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j-core
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.15
4
+ prerelease: 6
5
+ version: 2.0.0.alpha.1
6
6
  platform: java
7
7
  authors:
8
8
  - Andreas Ronge
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-04-27 00:00:00 Z
13
+ date: 2012-03-11 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: neo4j-community
@@ -18,9 +18,9 @@ dependencies:
18
18
  requirement: &id001 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
- - - ">="
21
+ - - "="
22
22
  - !ruby/object:Gem::Version
23
- version: 1.7.0
23
+ version: 1.6.1.alpha.1
24
24
  type: :runtime
25
25
  version_requirements: *id001
26
26
  description: |
@@ -37,10 +37,9 @@ extensions: []
37
37
  extra_rdoc_files:
38
38
  - README.rdoc
39
39
  files:
40
+ - lib/test.rb
40
41
  - lib/neo4j-core.rb
41
42
  - lib/neo4j/config.rb
42
- - lib/neo4j/algo.rb
43
- - lib/neo4j/cypher.rb
44
43
  - lib/neo4j/transaction.rb
45
44
  - lib/neo4j/neo4j.rb
46
45
  - lib/neo4j/neo4j.rb~
@@ -48,14 +47,13 @@ files:
48
47
  - lib/neo4j/relationship.rb
49
48
  - lib/neo4j-core/event_handler.rb
50
49
  - lib/neo4j-core/lazy_map.rb
51
- - lib/neo4j-core/hash_with_indifferent_access.rb
50
+ - lib/neo4j-core/version.rb~
52
51
  - lib/neo4j-core/database.rb
53
52
  - lib/neo4j-core/relationship_set.rb
54
53
  - lib/neo4j-core/version.rb
55
54
  - lib/neo4j-core/to_java.rb
56
55
  - lib/neo4j-core/node/node.rb
57
56
  - lib/neo4j-core/node/class_methods.rb
58
- - lib/neo4j-core/property/java.rb
59
57
  - lib/neo4j-core/property/property.rb
60
58
  - lib/neo4j-core/equal/equal.rb
61
59
  - lib/neo4j-core/traversal/rel_expander.rb
@@ -64,21 +62,17 @@ files:
64
62
  - lib/neo4j-core/traversal/traversal.rb
65
63
  - lib/neo4j-core/traversal/traverser.rb
66
64
  - lib/neo4j-core/traversal/evaluator.rb
65
+ - lib/neo4j-core/type_converters/type_converters.rb
67
66
  - lib/neo4j-core/rels/traverser.rb
68
67
  - lib/neo4j-core/rels/rels.rb
69
- - lib/neo4j-core/wrapper/wrapper.rb
70
- - lib/neo4j-core/wrapper/class_methods.rb
71
68
  - lib/neo4j-core/index/index_config.rb
72
69
  - lib/neo4j-core/index/indexer.rb
73
70
  - lib/neo4j-core/index/lucene_query.rb
74
71
  - lib/neo4j-core/index/indexer_registry.rb
75
- - lib/neo4j-core/index/unique_factory.rb
76
72
  - lib/neo4j-core/index/class_methods.rb
77
73
  - lib/neo4j-core/index/index.rb
78
74
  - lib/neo4j-core/relationship/class_methods.rb
79
75
  - lib/neo4j-core/relationship/relationship.rb
80
- - lib/neo4j-core/cypher/cypher.rb
81
- - lib/neo4j-core/cypher/result_wrapper.rb
82
76
  - config/neo4j/config.yml
83
77
  - README.rdoc
84
78
  - Gemfile
@@ -90,7 +84,7 @@ post_install_message:
90
84
  rdoc_options:
91
85
  - --quiet
92
86
  - --title
93
- - Neo4j::Core
87
+ - Neo4j.rb
94
88
  - --line-numbers
95
89
  - --main
96
90
  - README.rdoc
@@ -106,9 +100,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
100
  required_rubygems_version: !ruby/object:Gem::Requirement
107
101
  none: false
108
102
  requirements:
109
- - - ">="
103
+ - - ">"
110
104
  - !ruby/object:Gem::Version
111
- version: "0"
105
+ version: 1.3.1
112
106
  requirements: []
113
107
 
114
108
  rubyforge_project: neo4j-core
@@ -1,969 +0,0 @@
1
- module Neo4j
2
- module Core
3
-
4
- # This module contains a number of mixins and classes used by the neo4j.rb cypher DSL.
5
- # The Cypher DSL is evaluated in the context of {Neo4j::Cypher} which contains a number of methods (e.g. {Neo4j::Cypher#node})
6
- # which returns classes from this module.
7
- module Cypher
8
-
9
- module MathFunctions
10
- def abs(value=nil)
11
- _add_math_func(:abs, value)
12
- end
13
-
14
- def sqrt(value=nil)
15
- _add_math_func(:sqrt, value)
16
- end
17
-
18
- def round(value=nil)
19
- _add_math_func(:round, value)
20
- end
21
-
22
- def sign(value=nil)
23
- _add_math_func(:sign, value)
24
- end
25
-
26
- # @private
27
- def _add_math_func(name, value=nil)
28
- value ||= self.respond_to?(:var_name) ? self.var_name : to_s
29
- expressions.delete(self)
30
- Property.new(expressions, nil, name).to_function!(value)
31
- end
32
- end
33
-
34
- module MathOperator
35
- def -(other)
36
- ExprOp.new(self, other, '-')
37
- end
38
-
39
- def +(other)
40
- ExprOp.new(self, other, '+')
41
- end
42
- end
43
-
44
- module Comparable
45
- def <(other)
46
- ExprOp.new(self, other, '<')
47
- end
48
-
49
- def <=(other)
50
- ExprOp.new(self, other, '<=')
51
- end
52
-
53
- def =~(other)
54
- ExprOp.new(self, other, '=~')
55
- end
56
-
57
- def >(other)
58
- ExprOp.new(self, other, '>')
59
- end
60
-
61
- def >=(other)
62
- ExprOp.new(self, other, '>=')
63
- end
64
-
65
- ## Only in 1.9
66
- if RUBY_VERSION > "1.9.0"
67
- eval %{
68
- def !=(other)
69
- other.is_a?(String) ? ExprOp.new(self, other, "!=") : super
70
- end }
71
- end
72
-
73
- def ==(other)
74
- if other.is_a?(Fixnum) || other.is_a?(String) || other.is_a?(Regexp)
75
- ExprOp.new(self, other, "=")
76
- else
77
- super
78
- end
79
- end
80
- end
81
-
82
- module PredicateMethods
83
- def all?(&block)
84
- self.respond_to?(:iterable)
85
- Predicate.new(expressions, :op => 'all', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
86
- end
87
-
88
- def extract(&block)
89
- Predicate.new(expressions, :op => 'extract', :clause => :return, :input => input, :iterable => iterable, :predicate_block => block)
90
- end
91
-
92
- def filter(&block)
93
- Predicate.new(expressions, :op => 'filter', :clause => :return, :input => input, :iterable => iterable, :predicate_block => block)
94
- end
95
-
96
- def any?(&block)
97
- Predicate.new(@expressions, :op => 'any', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
98
- end
99
-
100
- def none?(&block)
101
- Predicate.new(@expressions, :op => 'none', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
102
- end
103
-
104
- def single?(&block)
105
- Predicate.new(@expressions, :op => 'single', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
106
- end
107
-
108
- end
109
-
110
- module Variable
111
- attr_accessor :return_method
112
-
113
- def distinct
114
- self.return_method = {:name => 'distinct', :bracket => false}
115
- self
116
- end
117
-
118
- def [](prop_name)
119
- Property.new(expressions, self, prop_name)
120
- end
121
-
122
- def as(v)
123
- @var_name = v
124
- self
125
- end
126
-
127
- # generates a <tt>ID</tt> cypher fragment.
128
- def neo_id
129
- Property.new(@expressions, self, 'ID').to_function!
130
- end
131
-
132
- # generates a <tt>has</tt> cypher fragment.
133
- def property?(p)
134
- p = Property.new(expressions, self, p)
135
- p.binary_operator("has")
136
- end
137
-
138
- # generates a <tt>is null</tt> cypher fragment.
139
- def exist?
140
- p = Property.new(expressions, self, p)
141
- p.binary_operator("", " is null")
142
- end
143
-
144
- # Can be used instead of [_classname] == klass
145
- def is_a?(klass)
146
- return super if klass.class != Class || !klass.respond_to?(:_load_wrapper)
147
- self[:_classname] == klass.to_s
148
- end
149
- end
150
-
151
- module Matchable
152
- # This operator means related to, without regard to type or direction.
153
- # @param [Symbol, #var_name] other either a node (Symbol, #var_name)
154
- # @return [MatchRelLeft, MatchNode]
155
- def <=>(other)
156
- MatchNode.new(self, other, expressions, :both)
157
- end
158
-
159
- # This operator means outgoing related to
160
- # @param [Symbol, #var_name, String] other the relationship
161
- # @return [MatchRelLeft, MatchNode]
162
- def >(other)
163
- MatchRelLeft.new(self, other, expressions, :outgoing)
164
- end
165
-
166
- # This operator means any direction related to
167
- # @param (see #>)
168
- # @return [MatchRelLeft, MatchNode]
169
- def -(other)
170
- MatchRelLeft.new(self, other, expressions, :both)
171
- end
172
-
173
- # This operator means incoming related to
174
- # @param (see #>)
175
- # @return [MatchRelLeft, MatchNode]
176
- def <(other)
177
- MatchRelLeft.new(self, other, expressions, :incoming)
178
- end
179
-
180
- # Outgoing relationship to other node
181
- # @param [Symbol, #var_name] other either a node (Symbol, #var_name)
182
- # @return [MatchRelLeft, MatchNode]
183
- def >>(other)
184
- MatchNode.new(self, other, expressions, :outgoing)
185
- end
186
-
187
- def outgoing(rel_type)
188
- node = NodeVar.new(@expressions, @variables)
189
- MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :outgoing) > node
190
- node
191
- end
192
-
193
- def incoming(rel_type)
194
- node = NodeVar.new(@expressions, @variables)
195
- MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :incoming) < node
196
- node
197
- end
198
-
199
- def both(rel_type)
200
- node = NodeVar.new(@expressions, @variables)
201
- MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :both) < node
202
- node
203
- end
204
-
205
- # Incoming relationship to other node
206
- # @param [Symbol, #var_name] other either a node (Symbol, #var_name)
207
- # @return [MatchRelLeft, MatchNode]
208
- def <<(other)
209
- MatchNode.new(self, other, expressions, :incoming)
210
- end
211
- end
212
-
213
- class Expression
214
- attr_reader :expressions
215
- attr_accessor :separator, :clause
216
-
217
- def initialize(expressions, clause)
218
- @clause = clause
219
- @expressions = expressions
220
- insert_last(clause)
221
- @separator = ","
222
- end
223
-
224
- def insert_last(clause)
225
- i = @expressions.reverse.index { |e| e.clause == clause }
226
- if i.nil?
227
- @expressions << self
228
- else
229
- pos = @expressions.size - i
230
- @expressions.insert(pos, self)
231
- end
232
- end
233
-
234
- def prefixes
235
- {:start => "START", :where => " WHERE", :match => " MATCH", :return => " RETURN", :order_by => " ORDER BY", :skip => " SKIP", :limit => " LIMIT"}
236
- end
237
-
238
- def prefix
239
- prefixes[clause]
240
- end
241
-
242
- def valid?
243
- true
244
- end
245
-
246
- end
247
-
248
- # A property is returned from a Variable by using the [] operator.
249
- #
250
- # It has a number of useful method like
251
- # <tt>count</tt>, <tt>sum</tt>, <tt>avg</tt>, <tt>min</tt>, <tt>max</tt>, <tt>collect</tt>, <tt>head</tt>, <tt>last</tt>, <tt>tail</tt>,
252
- #
253
- # @example
254
- # n=node(2, 3, 4); n[:name].collect
255
- # # same as START n0=node(2,3,4) RETURN collect(n0.property)
256
- class Property
257
- # @private
258
- attr_reader :expressions, :var_name
259
- include Comparable
260
- include MathOperator
261
- include MathFunctions
262
- include PredicateMethods
263
-
264
- def initialize(expressions, var, prop_name)
265
- @var = var.respond_to?(:var_name) ? var.var_name : var
266
- @expressions = expressions
267
- @prop_name = prop_name
268
- @var_name = @prop_name ? "#{@var.to_s}.#{@prop_name}" : @var.to_s
269
- end
270
-
271
- # @private
272
- def to_function!(var = @var.to_s)
273
- @var_name = "#{@prop_name}(#{var})"
274
- self
275
- end
276
-
277
- # Make it possible to rename a property with a different name (AS)
278
- def as(new_name)
279
- @var_name = "#{@var_name} AS #{new_name}"
280
- end
281
-
282
- # required by the Predicate Methods Module
283
- # @see PredicateMethods
284
- # @private
285
- def iterable
286
- var_name
287
- end
288
-
289
- def input
290
- self
291
- end
292
-
293
- # @private
294
- def in?(values)
295
- binary_operator("", " IN [#{values.map { |x| %Q["#{x}"] }.join(',')}]")
296
- end
297
-
298
- # Only return distinct values/nodes/rels/paths
299
- def distinct
300
- @var_name = "distinct #{@var_name}"
301
- self
302
- end
303
-
304
- def length
305
- @prop_name = "length"
306
- to_function!
307
- self
308
- end
309
-
310
- %w[count sum avg min max collect head last tail].each do |meth_name|
311
- define_method(meth_name) do
312
- function(meth_name.to_s)
313
- end
314
- end
315
-
316
- # @private
317
- def function(func_name_pre, func_name_post = "")
318
- ExprOp.new(self, nil, func_name_pre, func_name_post)
319
- end
320
-
321
- # @private
322
- def binary_operator(op, post_fix = "")
323
- ExprOp.new(self, nil, op, post_fix).binary!
324
- end
325
- end
326
-
327
- class Start < Expression
328
- # @private
329
- attr_reader :var_name
330
- include Variable
331
- include Matchable
332
-
333
- def initialize(var_name, expressions)
334
- @var_name = "#{var_name}#{expressions.size}"
335
- super(expressions, :start)
336
- end
337
-
338
- end
339
-
340
- # Can be created from a <tt>node</tt> dsl method.
341
- class StartNode < Start
342
- # @private
343
- attr_reader :nodes
344
-
345
- def initialize(nodes, expressions)
346
- super("n", expressions)
347
-
348
- @nodes = nodes.map { |n| n.respond_to?(:neo_id) ? n.neo_id : n }
349
- end
350
-
351
- def to_s
352
- "#{var_name}=node(#{nodes.join(',')})"
353
- end
354
- end
355
-
356
-
357
- # Can be created from a <tt>rel</tt> dsl method.
358
- class StartRel < Start
359
- # @private
360
- attr_reader :rels
361
-
362
- def initialize(rels, expressions)
363
- super("r", expressions)
364
- @rels = rels.map { |n| n.respond_to?(:neo_id) ? n.neo_id : n }
365
- end
366
-
367
- def to_s
368
- "#{var_name}=relationship(#{rels.join(',')})"
369
- end
370
- end
371
-
372
- class NodeQuery < Start
373
- attr_reader :index_name, :query
374
-
375
- def initialize(index_class, query, index_type, expressions)
376
- super("n", expressions)
377
- @index_name = index_class.index_name_for_type(index_type)
378
- @query = query
379
- end
380
-
381
- def to_s
382
- "#{var_name}=node:#{index_name}(#{query})"
383
- end
384
- end
385
-
386
- class NodeLookup < Start
387
- attr_reader :index_name, :query
388
-
389
- def initialize(index_class, key, value, expressions)
390
- super("n", expressions)
391
- index_type = index_class.index_type(key.to_s)
392
- raise "No index on #{index_class} property #{key}" unless index_type
393
- @index_name = index_class.index_name_for_type(index_type)
394
- @query = %Q[#{key}="#{value}"]
395
- end
396
-
397
- def to_s
398
- %Q[#{var_name}=node:#{index_name}(#{query})]
399
- end
400
-
401
- end
402
-
403
- # The return statement in the cypher query
404
- class Return < Expression
405
- attr_reader :var_name
406
-
407
- def initialize(name_or_ref, expressions, opts = {})
408
- super(expressions, :return)
409
- @name_or_ref = name_or_ref
410
- @name_or_ref.referenced! if @name_or_ref.respond_to?(:referenced!)
411
- @var_name = @name_or_ref.respond_to?(:var_name) ? @name_or_ref.var_name : @name_or_ref.to_s
412
- opts.each_pair { |k, v| self.send(k, v) }
413
- end
414
-
415
- # @private
416
- def return_method
417
- @name_or_ref.respond_to?(:return_method) && @name_or_ref.return_method
418
- end
419
-
420
- # @private
421
- def as_return_method
422
- if return_method[:bracket]
423
- "#{return_method[:name]}(#@var_name)"
424
- else
425
- "#{return_method[:name]} #@var_name"
426
- end
427
- end
428
-
429
- # Specifies an <tt>ORDER BY</tt> cypher query
430
- # @param [Property] props the properties which should be sorted
431
- # @return self
432
- def asc(*props)
433
- @order_by ||= OrderBy.new(expressions)
434
- @order_by.asc(props)
435
- self
436
- end
437
-
438
- # Specifies an <tt>ORDER BY</tt> cypher query
439
- # @param [Property] props the properties which should be sorted
440
- # @return self
441
- def desc(*props)
442
- @order_by ||= OrderBy.new(expressions)
443
- @order_by.desc(props)
444
- self
445
- end
446
-
447
- # Creates a <tt>SKIP</tt> cypher clause
448
- # @param [Fixnum] val the number of entries to skip
449
- # @return self
450
- def skip(val)
451
- Skip.new(expressions, val)
452
- self
453
- end
454
-
455
- # Creates a <tt>LIMIT</tt> cypher clause
456
- # @param [Fixnum] val the number of entries to limit
457
- # @return self
458
- def limit(val)
459
- Limit.new(expressions, val)
460
- self
461
- end
462
-
463
- def to_s
464
- return_method ? as_return_method : var_name.to_s
465
- end
466
- end
467
-
468
- # Can be used to skip result from a return clause
469
- class Skip < Expression
470
- def initialize(expressions, value)
471
- super(expressions, :skip)
472
- @value = value
473
- end
474
-
475
- def to_s
476
- @value
477
- end
478
- end
479
-
480
- # Can be used to limit result from a return clause
481
- class Limit < Expression
482
- def initialize(expressions, value)
483
- super(expressions, :limit)
484
- @value = value
485
- end
486
-
487
- def to_s
488
- @value
489
- end
490
- end
491
-
492
- class OrderBy < Expression
493
- def initialize(expressions)
494
- super(expressions, :order_by)
495
- @orders = []
496
- end
497
-
498
- def asc(props)
499
- @orders << [:asc, props]
500
- end
501
-
502
- def desc(props)
503
- @orders << [:desc, props]
504
- end
505
-
506
- def to_s
507
- @orders.map do |pair|
508
- if pair[0] == :asc
509
- pair[1].map(&:var_name).join(', ')
510
- else
511
- pair[1].map(&:var_name).join(', ') + " DESC"
512
- end
513
- end.join(', ')
514
- end
515
- end
516
-
517
- # Created from a node's match operator like >> or <.
518
- class Match < Expression
519
- # @private
520
- attr_reader :dir, :expressions, :left, :right, :var_name, :dir_op
521
- # @private
522
- attr_accessor :algorithm, :next, :prev
523
- include Variable
524
-
525
- def initialize(left, right, expressions, dir, dir_op)
526
- super(expressions, :match)
527
- @var_name = "m#{expressions.size}"
528
- @dir = dir
529
- @dir_op = dir_op
530
- @prev = left if left.is_a?(Match)
531
- @left = left
532
- @right = right
533
- end
534
-
535
-
536
- # Generates a <tt>x in nodes(m3)</tt> cypher expression.
537
- #
538
- # @example
539
- # p.nodes.all? { |x| x[:age] > 30 }
540
- def nodes
541
- Entities.new(@expressions, "nodes", self)
542
- end
543
-
544
- # Generates a <tt>x in relationships(m3)</tt> cypher expression.
545
- #
546
- # @example
547
- # p.relationships.all? { |x| x[:age] > 30 }
548
- def rels
549
- Entities.new(@expressions, "relationships", self)
550
- end
551
-
552
- # returns the length of the path
553
- def length
554
- self.return_method = {:name => 'length', :bracket => true}
555
- self
556
- end
557
-
558
- # @private
559
- def find_match_start
560
- c = self
561
- while (c.prev) do
562
- c = c.prev
563
- end
564
- c
565
- end
566
-
567
- # @private
568
- def left_var_name
569
- @left.respond_to?(:var_name) ? @left.var_name : @left.to_s
570
- end
571
-
572
- # @private
573
- def right_var_name
574
- @right.respond_to?(:var_name) ? @right.var_name : @right.to_s
575
- end
576
-
577
- # @private
578
- def right_expr
579
- @right.respond_to?(:expr) ? @right.expr : right_var_name
580
- end
581
-
582
- # @private
583
- def referenced!
584
- @referenced = true
585
- end
586
-
587
- # @private
588
- def referenced?
589
- !!@referenced
590
- end
591
-
592
- # @private
593
- def to_s
594
- curr = find_match_start
595
- result = (referenced? || curr.referenced?) ? "#{var_name} = " : ""
596
- result << (algorithm ? "#{algorithm}(" : "")
597
- begin
598
- result << curr.expr
599
- end while (curr = curr.next)
600
- result << ")" if algorithm
601
- result
602
- end
603
- end
604
-
605
- # The left part of a match clause, e.g. node < rel(':friends')
606
- # Can return {MatchRelRight} using a match operator method.
607
- class MatchRelLeft < Match
608
- def initialize(left, right, expressions, dir)
609
- super(left, right, expressions, dir, dir == :incoming ? '<-' : '-')
610
- end
611
-
612
- # @param [Symbol,NodeVar,String] other part of the match cypher statement.
613
- # @return [MatchRelRight] the right part of an relationship cypher query.
614
- def >(other)
615
- expressions.delete(self)
616
- self.next = MatchRelRight.new(self, other, expressions, :outgoing)
617
- end
618
-
619
- # @see #>
620
- # @return (see #>)
621
- def <(other)
622
- expressions.delete(self)
623
- self.next = MatchRelRight.new(self, other, expressions, :incoming)
624
- end
625
-
626
- # @see #>
627
- # @return (see #>)
628
- def -(other)
629
- expressions.delete(self)
630
- self.next = MatchRelRight.new(self, other, expressions, :both)
631
- end
632
-
633
- # @return [String] a cypher string for this match.
634
- def expr
635
- if prev
636
- # we have chained more then one relationships in a match expression
637
- "#{dir_op}[#{right_expr}]"
638
- else
639
- # the right is an relationship and could be an expressions, e.g "r?"
640
- "(#{left_var_name})#{dir_op}[#{right_expr}]"
641
- end
642
- end
643
- end
644
-
645
- class MatchRelRight < Match
646
- # @param left the left part of the query
647
- # @param [Symbol,NodeVar,String] right part of the match cypher statement.
648
- def initialize(left, right, expressions, dir)
649
- super(left, right, expressions, dir, dir == :outgoing ? '->' : '-')
650
- end
651
-
652
- # @param [Symbol,NodeVar,String] other part of the match cypher statement.
653
- # @return [MatchRelLeft] the right part of an relationship cypher query.
654
- def >(other)
655
- expressions.delete(self)
656
- self.next = MatchRelLeft.new(self, other, expressions, :outgoing)
657
- end
658
-
659
- # @see #>
660
- # @return (see #>)
661
- def <(other)
662
- expressions.delete(self)
663
- self.next = MatchRelLeft.new(self, other, expressions, :incoming)
664
- end
665
-
666
- # @see #>
667
- # @return (see #>)
668
- def -(other)
669
- expressions.delete(self)
670
- self.next = MatchRelLeft.new(self, other, expressions, :both)
671
- end
672
-
673
- # @return [String] a cypher string for this match.
674
- def expr
675
- "#{dir_op}(#{right_var_name})"
676
- end
677
-
678
- # negate this match
679
- def not
680
- expressions.delete(self)
681
- ExprOp.new(left, nil, "not").binary!
682
- end
683
-
684
- if RUBY_VERSION > "1.9.0"
685
- eval %{
686
- def !
687
- expressions.delete(self)
688
- ExprOp.new(left, nil, "not").binary!
689
- end
690
- }
691
- end
692
-
693
- end
694
-
695
- # The right part of a match clause (node_b), e.g. node_a > rel(':friends') > node_b
696
- #
697
- class MatchNode < Match
698
- attr_reader :dir_op
699
-
700
- def initialize(left, right, expressions, dir)
701
- dir_op = case dir
702
- when :outgoing then
703
- "-->"
704
- when :incoming then
705
- "<--"
706
- when :both then
707
- "--"
708
- end
709
- super(left, right, expressions, dir, dir_op)
710
- end
711
-
712
- # @return [String] a cypher string for this match.
713
- def expr
714
- if prev
715
- # we have chained more then one relationships in a match expression
716
- "#{dir_op}(#{right_expr})"
717
- else
718
- # the right is an relationship and could be an expressions, e.g "r?"
719
- "(#{left_var_name})#{dir_op}(#{right_expr})"
720
- end
721
- end
722
-
723
- def <<(other)
724
- expressions.delete(self)
725
- self.next = MatchNode.new(self, other, expressions, :incoming)
726
- end
727
-
728
- def >>(other)
729
- expressions.delete(self)
730
- self.next = MatchNode.new(self, other, expressions, :outgoing)
731
- end
732
-
733
- # @param [Symbol,NodeVar,String] other part of the match cypher statement.
734
- # @return [MatchRelRight] the right part of an relationship cypher query.
735
- def >(other)
736
- expressions.delete(self)
737
- self.next = MatchRelLeft.new(self, other, expressions, :outgoing)
738
- end
739
-
740
- # @see #>
741
- # @return (see #>)
742
- def <(other)
743
- expressions.delete(self)
744
- self.next = MatchRelLeft.new(self, other, expressions, :incoming)
745
- end
746
-
747
- # @see #>
748
- # @return (see #>)
749
- def -(other)
750
- expressions.delete(self)
751
- self.next = MatchRelLeft.new(self, other, expressions, :both)
752
- end
753
-
754
- end
755
-
756
- # Represents an unbound node variable used in match statements
757
- class NodeVar
758
- include Variable
759
- include Matchable
760
-
761
- # @return the name of the variable
762
- attr_reader :var_name
763
- attr_reader :expressions
764
-
765
- def initialize(expressions, variables)
766
- variables ||= []
767
- @var_name = "v#{variables.size}"
768
- variables << self
769
- @variables = variables
770
- @expressions = expressions
771
- end
772
-
773
- # @return [String] a cypher string for this node variable
774
- def to_s
775
- var_name
776
- end
777
-
778
- end
779
-
780
- # represent an unbound relationship variable used in match,where,return statement
781
- class RelVar
782
- include Variable
783
-
784
- attr_reader :var_name, :expr, :expressions
785
-
786
- def initialize(expressions, variables, expr)
787
- variables << self
788
- @expr = expr
789
- @expressions = expressions
790
- guess = expr ? /([[:alpha:]]*)/.match(expr)[1] : ""
791
- @var_name = guess.empty? ? "v#{variables.size}" : guess
792
- end
793
-
794
- def rel_type
795
- Property.new(@expressions, self, 'type').to_function!
796
- end
797
-
798
- # @return [String] a cypher string for this relationship variable
799
- def to_s
800
- var_name
801
- end
802
-
803
- end
804
-
805
- class ExprOp < Expression
806
- attr_reader :left, :right, :op, :neg, :post_fix
807
- include MathFunctions
808
-
809
- def initialize(left, right, op, post_fix = "")
810
- super(left.expressions, :where)
811
- @op = op
812
- @post_fix = post_fix
813
- self.expressions.delete(left)
814
- self.expressions.delete(right)
815
- @left = quote(left)
816
- if regexp?(right)
817
- @op = "=~"
818
- @right = to_regexp(right)
819
- else
820
- @right = right && quote(right)
821
- end
822
- @neg = nil
823
- end
824
-
825
- def separator
826
- " "
827
- end
828
-
829
- def quote(val)
830
- if val.respond_to?(:var_name) && !val.kind_of?(Match)
831
- val.var_name
832
- else
833
- val.is_a?(String) ? %Q["#{val}"] : val
834
- end
835
- end
836
-
837
- def regexp?(right)
838
- @op == "=~" || right.is_a?(Regexp)
839
- end
840
-
841
- def to_regexp(val)
842
- %Q[/#{val.respond_to?(:source) ? val.source : val.to_s}/]
843
- end
844
-
845
- def count
846
- ExprOp.new(self, nil, 'count')
847
- end
848
-
849
- def &(other)
850
- ExprOp.new(self, other, "and")
851
- end
852
-
853
- def |(other)
854
- ExprOp.new(self, other, "or")
855
- end
856
-
857
- def -@
858
- @neg = "not"
859
- self
860
- end
861
-
862
- def not
863
- @neg = "not"
864
- self
865
- end
866
-
867
- # Only in 1.9
868
- if RUBY_VERSION > "1.9.0"
869
- eval %{
870
- def !
871
- @neg = "not"
872
- self
873
- end
874
- }
875
- end
876
-
877
- def left_to_s
878
- left.is_a?(ExprOp) ? "(#{left})" : left
879
- end
880
-
881
- def right_to_s
882
- right.is_a?(ExprOp) ? "(#{right})" : right
883
- end
884
-
885
- def binary!
886
- @binary = true
887
- self
888
- end
889
-
890
- def valid?
891
- # puts "valid? @binary=#{@binary} (#@left #@op #@right) in clause #{clause} ret #{@binary ? !!@left : !!@left && !!@right}"
892
- # it is only valid in a where clause if it's either binary or it has right and left values
893
- @binary ? @left : @left && @right
894
- end
895
-
896
- def to_s
897
- if @right
898
- neg ? "#{neg}(#{left_to_s} #{op} #{right_to_s})" : "#{left_to_s} #{op} #{right_to_s}"
899
- else
900
- # binary operator
901
- neg ? "#{neg}#{op}(#{left_to_s}#{post_fix})" : "#{op}(#{left_to_s}#{post_fix})"
902
- end
903
- end
904
- end
905
-
906
- class Where < Expression
907
- def initialize(expressions, where_statement = nil)
908
- super(expressions, :where)
909
- @where_statement = where_statement
910
- end
911
-
912
- def to_s
913
- @where_statement.to_s
914
- end
915
- end
916
-
917
- class Predicate < Expression
918
- attr_accessor :params
919
-
920
- def initialize(expressions, params)
921
- @params = params
922
- @identifier = :x
923
- params[:input].referenced! if params[:input].respond_to?(:referenced!)
924
- super(expressions, params[:clause])
925
- end
926
-
927
- def identifier(i)
928
- @identifier = i
929
- self
930
- end
931
-
932
- def to_s
933
- input = params[:input]
934
- if input.kind_of?(Property)
935
- yield_param = Property.new([], @identifier, nil)
936
- args = ""
937
- else
938
- yield_param = NodeVar.new([], []).as(@identifier.to_sym)
939
- args = "(#{input.var_name})"
940
- end
941
- context = Neo4j::Cypher.new(yield_param, &params[:predicate_block])
942
- context.expressions.each { |e| e.clause = nil }
943
- if params[:clause] == :return
944
- where_or_colon = ':'
945
- else
946
- where_or_colon = 'WHERE'
947
- end
948
- predicate_value = context.to_s[1..-1] # skip separator ,
949
- "#{params[:op]}(#@identifier in #{params[:iterable]}#{args} #{where_or_colon} #{predicate_value})"
950
- end
951
- end
952
-
953
- class Entities
954
- include PredicateMethods
955
- attr_reader :input, :expressions, :iterable
956
-
957
- def initialize(expressions, iterable, input)
958
- @iterable = iterable
959
- @input = input
960
- @expressions = expressions
961
- end
962
-
963
- end
964
-
965
- end
966
-
967
- end
968
-
969
- end