pacer 0.9.1.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +8 -0
- data/.document +5 -0
- data/.gitignore +26 -0
- data/.rspec +1 -0
- data/.rvmrc +0 -0
- data/CONTRIBUTORS +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/README.md +187 -0
- data/Rakefile +49 -0
- data/autotest/discover.rb +1 -0
- data/bin/autospec +16 -0
- data/bin/autotest +16 -0
- data/bin/rake +16 -0
- data/bin/rcov +16 -0
- data/bin/rspec +16 -0
- data/bin/yard +16 -0
- data/bin/yardoc +16 -0
- data/lib/pacer/blueprints/extensions.rb +77 -0
- data/lib/pacer/blueprints/multi_graph.rb +121 -0
- data/lib/pacer/blueprints/ruby_graph.rb +199 -0
- data/lib/pacer/blueprints/tg.rb +100 -0
- data/lib/pacer/blueprints.rb +4 -0
- data/lib/pacer/core/graph/edges_route.rb +92 -0
- data/lib/pacer/core/graph/element_route.rb +171 -0
- data/lib/pacer/core/graph/graph_index_route.rb +48 -0
- data/lib/pacer/core/graph/graph_route.rb +55 -0
- data/lib/pacer/core/graph/mixed_route.rb +96 -0
- data/lib/pacer/core/graph/vertices_route.rb +220 -0
- data/lib/pacer/core/graph.rb +13 -0
- data/lib/pacer/core/route.rb +502 -0
- data/lib/pacer/core/side_effect.rb +11 -0
- data/lib/pacer/core.rb +8 -0
- data/lib/pacer/exceptions.rb +11 -0
- data/lib/pacer/extensions/block_filter_element.rb +22 -0
- data/lib/pacer/extensions.rb +6 -0
- data/lib/pacer/filter/block_filter.rb +31 -0
- data/lib/pacer/filter/collection_filter.rb +109 -0
- data/lib/pacer/filter/empty_filter.rb +70 -0
- data/lib/pacer/filter/future_filter.rb +68 -0
- data/lib/pacer/filter/index_filter.rb +30 -0
- data/lib/pacer/filter/loop_filter.rb +95 -0
- data/lib/pacer/filter/object_filter.rb +55 -0
- data/lib/pacer/filter/property_filter/edge_filters.rb +93 -0
- data/lib/pacer/filter/property_filter/filters.rb +269 -0
- data/lib/pacer/filter/property_filter.rb +111 -0
- data/lib/pacer/filter/random_filter.rb +13 -0
- data/lib/pacer/filter/range_filter.rb +104 -0
- data/lib/pacer/filter/uniq_filter.rb +12 -0
- data/lib/pacer/filter/where_filter/node_visitor.rb +280 -0
- data/lib/pacer/filter/where_filter.rb +47 -0
- data/lib/pacer/filter.rb +17 -0
- data/lib/pacer/function_resolver.rb +43 -0
- data/lib/pacer/graph/edge_mixin.rb +127 -0
- data/lib/pacer/graph/element_mixin.rb +202 -0
- data/lib/pacer/graph/graph_indices_mixin.rb +93 -0
- data/lib/pacer/graph/graph_mixin.rb +361 -0
- data/lib/pacer/graph/graph_transactions_mixin.rb +207 -0
- data/lib/pacer/graph/index_mixin.rb +30 -0
- data/lib/pacer/graph/vertex_mixin.rb +119 -0
- data/lib/pacer/graph.rb +14 -0
- data/lib/pacer/pipe/blackbox_pipeline.rb +48 -0
- data/lib/pacer/pipe/block_filter_pipe.rb +38 -0
- data/lib/pacer/pipe/collection_filter_pipe.rb +10 -0
- data/lib/pacer/pipe/cross_product_transform_pipe.rb +48 -0
- data/lib/pacer/pipe/enumerable_pipe.rb +30 -0
- data/lib/pacer/pipe/expandable_pipe.rb +63 -0
- data/lib/pacer/pipe/id_collection_filter_pipe.rb +33 -0
- data/lib/pacer/pipe/is_empty_pipe.rb +30 -0
- data/lib/pacer/pipe/is_unique_pipe.rb +61 -0
- data/lib/pacer/pipe/label_collection_filter_pipe.rb +21 -0
- data/lib/pacer/pipe/label_prefix_pipe.rb +21 -0
- data/lib/pacer/pipe/loop_pipe.rb +86 -0
- data/lib/pacer/pipe/map_pipe.rb +36 -0
- data/lib/pacer/pipe/never_pipe.rb +9 -0
- data/lib/pacer/pipe/process_pipe.rb +37 -0
- data/lib/pacer/pipe/property_comparison_pipe.rb +40 -0
- data/lib/pacer/pipe/ruby_pipe.rb +25 -0
- data/lib/pacer/pipe/simple_visitor_pipe.rb +43 -0
- data/lib/pacer/pipe/stream_sort_pipe.rb +84 -0
- data/lib/pacer/pipe/stream_uniq_pipe.rb +33 -0
- data/lib/pacer/pipe/type_filter_pipe.rb +22 -0
- data/lib/pacer/pipe/unary_transform_pipe.rb +59 -0
- data/lib/pacer/pipe/variable_store_iterator_wrapper.rb +26 -0
- data/lib/pacer/pipe/visitor_pipe.rb +67 -0
- data/lib/pacer/pipes.rb +61 -0
- data/lib/pacer/route/mixin/bulk_operations.rb +52 -0
- data/lib/pacer/route/mixin/route_operations.rb +107 -0
- data/lib/pacer/route/mixin/variable_route_module.rb +26 -0
- data/lib/pacer/route/mixins.rb +3 -0
- data/lib/pacer/route.rb +228 -0
- data/lib/pacer/routes.rb +6 -0
- data/lib/pacer/side_effect/aggregate.rb +31 -0
- data/lib/pacer/side_effect/counted.rb +30 -0
- data/lib/pacer/side_effect/group_count.rb +44 -0
- data/lib/pacer/side_effect/is_unique.rb +32 -0
- data/lib/pacer/side_effect/section.rb +25 -0
- data/lib/pacer/side_effect/visitor.rb +37 -0
- data/lib/pacer/side_effect.rb +11 -0
- data/lib/pacer/support/array_list.rb +28 -0
- data/lib/pacer/support/enumerable.rb +100 -0
- data/lib/pacer/support/hash.rb +9 -0
- data/lib/pacer/support/iterator_mixins.rb +110 -0
- data/lib/pacer/support/native_exception.rb +22 -0
- data/lib/pacer/support/proc.rb +16 -0
- data/lib/pacer/support.rb +10 -0
- data/lib/pacer/transform/cap.rb +50 -0
- data/lib/pacer/transform/gather.rb +9 -0
- data/lib/pacer/transform/has_count_cap.rb +41 -0
- data/lib/pacer/transform/join.rb +181 -0
- data/lib/pacer/transform/map.rb +23 -0
- data/lib/pacer/transform/path.rb +50 -0
- data/lib/pacer/transform/process.rb +23 -0
- data/lib/pacer/transform/scatter.rb +23 -0
- data/lib/pacer/transform/sort_section.rb +103 -0
- data/lib/pacer/transform/stream_sort.rb +21 -0
- data/lib/pacer/transform/stream_uniq.rb +21 -0
- data/lib/pacer/transform.rb +16 -0
- data/lib/pacer/utils/graph_analysis.rb +112 -0
- data/lib/pacer/utils/trie.rb +93 -0
- data/lib/pacer/utils/tsort.rb +65 -0
- data/lib/pacer/utils/y_files.rb +127 -0
- data/lib/pacer/utils.rb +10 -0
- data/lib/pacer/version.rb +13 -0
- data/lib/pacer/wrappers/edge_wrapper.rb +51 -0
- data/lib/pacer/wrappers/element_wrapper.rb +78 -0
- data/lib/pacer/wrappers/new_element.rb +106 -0
- data/lib/pacer/wrappers/vertex_wrapper.rb +51 -0
- data/lib/pacer/wrappers.rb +19 -0
- data/lib/pacer-0.9.1.1-standalone.jar +0 -0
- data/lib/pacer.rb +290 -0
- data/pacer.gemspec +30 -0
- data/pom/standalone.xml +22 -0
- data/pom.xml +124 -0
- data/samples/grateful-dead.xml +26380 -0
- data/samples/grateful_dead.rb +63 -0
- data/samples/profile.rb +15 -0
- data/spec/data/grateful-dead.xml +26380 -0
- data/spec/data/pacer.graphml +319 -0
- data/spec/pacer/blueprints/dex_spec.rb +172 -0
- data/spec/pacer/blueprints/neo4j_spec.rb +177 -0
- data/spec/pacer/blueprints/tg_spec.rb +128 -0
- data/spec/pacer/core/graph/edges_route_spec.rb +52 -0
- data/spec/pacer/core/graph/element_route_spec.rb +46 -0
- data/spec/pacer/core/graph/graph_route_spec.rb +94 -0
- data/spec/pacer/core/graph/vertices_route_spec.rb +169 -0
- data/spec/pacer/core/route_spec.rb +197 -0
- data/spec/pacer/filter/collection_filter_spec.rb +19 -0
- data/spec/pacer/filter/empty_filter_spec.rb +29 -0
- data/spec/pacer/filter/future_filter_spec.rb +97 -0
- data/spec/pacer/filter/loop_filter_spec.rb +31 -0
- data/spec/pacer/filter/property_filter_spec.rb +111 -0
- data/spec/pacer/filter/random_filter_spec.rb +17 -0
- data/spec/pacer/filter/uniq_filter_spec.rb +18 -0
- data/spec/pacer/filter/where_filter_spec.rb +93 -0
- data/spec/pacer/graph/edge_mixin_spec.rb +116 -0
- data/spec/pacer/graph/element_mixin_spec.rb +297 -0
- data/spec/pacer/graph/graph_mixin_spec.rb +538 -0
- data/spec/pacer/graph/index_mixin_spec.rb +0 -0
- data/spec/pacer/graph/vertex_mixin_spec.rb +192 -0
- data/spec/pacer/pipe/block_filter_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/labels_filter_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/ruby_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/type_filter_pipe_spec.rb +0 -0
- data/spec/pacer/route/mixin/base_spec.rb +419 -0
- data/spec/pacer/route/mixin/bulk_operations_spec.rb +30 -0
- data/spec/pacer/route/mixin/route_operations_spec.rb +127 -0
- data/spec/pacer/support/array_list_spec.rb +0 -0
- data/spec/pacer/support/enumerable_spec.rb +115 -0
- data/spec/pacer/transform/join_spec.rb +138 -0
- data/spec/pacer/transform/path_spec.rb +54 -0
- data/spec/pacer/utils/tsort_spec.rb +89 -0
- data/spec/pacer/wrapper/edge_wrapper_spec.rb +33 -0
- data/spec/pacer/wrapper/element_wrapper_spec.rb +169 -0
- data/spec/pacer/wrapper/vertex_wrapper_spec.rb +33 -0
- data/spec/pacer_spec.rb +0 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/support/contexts.rb +14 -0
- data/spec/support/graph_runner.rb +142 -0
- data/spec/support/matchers.rb +19 -0
- data/spec/support/use_transactions.rb +31 -0
- data/spec/tackle/simple_mixin.rb +21 -0
- data/spec/tackle/tinkerpop_graph_mixins.rb +60 -0
- metadata +364 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'pacer/filter/property_filter/filters'
|
2
|
+
require 'pacer/filter/property_filter/edge_filters'
|
3
|
+
|
4
|
+
module Pacer
|
5
|
+
class Route
|
6
|
+
class << self
|
7
|
+
def filters(filters)
|
8
|
+
if filters? filters
|
9
|
+
filters
|
10
|
+
elsif filters? filters.first
|
11
|
+
filters.first
|
12
|
+
else
|
13
|
+
Pacer::Filter::PropertyFilter::Filters.new(filters)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def edge_filters(filters)
|
18
|
+
if filters? filters
|
19
|
+
filters
|
20
|
+
elsif filters? filters.first
|
21
|
+
filters.first
|
22
|
+
else
|
23
|
+
Pacer::Filter::PropertyFilter::EdgeFilters.new(filters)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def filters?(filters)
|
28
|
+
filters.is_a? Pacer::Filter::PropertyFilter::Filters
|
29
|
+
end
|
30
|
+
|
31
|
+
def property_filter_before(base, filters, block)
|
32
|
+
filters = Pacer::Route.edge_filters(filters)
|
33
|
+
filters.blocks = [block] if block
|
34
|
+
if filters.extensions_only? and base.is_a? Route
|
35
|
+
base.wrapper ||= filters.wrapper if filters.wrapper
|
36
|
+
base.add_extensions(filters.extensions)
|
37
|
+
yield base
|
38
|
+
elsif filters and filters.any?
|
39
|
+
yield new(:back => base, :filter => :property, :filters => filters)
|
40
|
+
else
|
41
|
+
yield base
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def property_filter(base, filters, block)
|
46
|
+
filters = Pacer::Route.edge_filters(filters)
|
47
|
+
filters.blocks = [block] if block
|
48
|
+
if filters.extensions_only? and base.is_a? Route
|
49
|
+
base.wrapper ||= filters.wrapper if filters.wrapper
|
50
|
+
base.add_extensions(filters.extensions)
|
51
|
+
elsif filters and filters.any?
|
52
|
+
new(:back => base, :filter => :property, :filters => filters)
|
53
|
+
elsif Pacer.vertex? base
|
54
|
+
new(:back => base, :pipe_class => Pacer::Pipes::IdentityPipe)
|
55
|
+
elsif Pacer.edge? base
|
56
|
+
new(:back => base, :pipe_class => Pacer::Pipes::IdentityPipe)
|
57
|
+
else
|
58
|
+
base
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Filter
|
65
|
+
module PropertyFilter
|
66
|
+
#import com.tinkerpop.pipes.filter.LabelCollectionFilterPipe
|
67
|
+
import com.tinkerpop.pipes.filter.PropertyFilterPipe
|
68
|
+
|
69
|
+
def filters=(f)
|
70
|
+
if f.is_a? Filters
|
71
|
+
@filters = f
|
72
|
+
else
|
73
|
+
@filters = EdgeFilters.new(f)
|
74
|
+
end
|
75
|
+
self.wrapper ||= f.wrapper if f.wrapper
|
76
|
+
add_extensions f.extensions
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return an array of filter options for the current route.
|
80
|
+
def filters
|
81
|
+
@filters ||= EdgeFilters.new(nil)
|
82
|
+
end
|
83
|
+
|
84
|
+
def block=(block)
|
85
|
+
if block
|
86
|
+
filters.blocks = [block]
|
87
|
+
else
|
88
|
+
filters.blocks = []
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def block
|
93
|
+
filters.blocks.first
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
def build_pipeline
|
99
|
+
filters.build_pipeline(self, *pipe_source)
|
100
|
+
end
|
101
|
+
|
102
|
+
def inspect_string
|
103
|
+
if filters.any?
|
104
|
+
"#{inspect_class_name}(#{filters})"
|
105
|
+
else
|
106
|
+
inspect_class_name
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Core
|
3
|
+
module Route
|
4
|
+
# Return elements based on a bias:1 chance.
|
5
|
+
#
|
6
|
+
# If given an integer (n) > 0, bias is calcualated at 1 / n.
|
7
|
+
def random(bias = 0.5)
|
8
|
+
bias = 1 / bias.to_f if bias.is_a? Fixnum and bias > 0
|
9
|
+
chain_route :pipe_class => Pacer::Pipes::RandomFilterPipe, :pipe_args => bias
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Routes
|
3
|
+
module RouteOperations
|
4
|
+
def range(from, to)
|
5
|
+
args = { :filter => :range }
|
6
|
+
args[:begin] = from if from
|
7
|
+
args[:end] = to if to
|
8
|
+
chain_route args
|
9
|
+
end
|
10
|
+
|
11
|
+
def limit(max)
|
12
|
+
chain_route :filter => :range, :limit => max
|
13
|
+
end
|
14
|
+
|
15
|
+
def offset(amount)
|
16
|
+
chain_route :filter => :range, :offset => amount
|
17
|
+
end
|
18
|
+
|
19
|
+
def at(pos)
|
20
|
+
chain_route :filter => :range, :index => pos
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Filter
|
26
|
+
module RangeFilter
|
27
|
+
def limit(n = nil)
|
28
|
+
@limit = n
|
29
|
+
if range.begin == -1
|
30
|
+
@range = range.begin...n
|
31
|
+
else
|
32
|
+
@range = range.begin...(range.begin + n)
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def limit=(n)
|
38
|
+
limit n
|
39
|
+
n
|
40
|
+
end
|
41
|
+
|
42
|
+
def offset(n = nil)
|
43
|
+
s = n
|
44
|
+
s += 1 if range.begin == -1
|
45
|
+
if range.end == -1
|
46
|
+
@range = (range.begin + s)..-1
|
47
|
+
elsif range.exclude_end?
|
48
|
+
@range = (range.begin + s)...(range.end + n)
|
49
|
+
else
|
50
|
+
@range = (range.begin + s)..(range.end + n)
|
51
|
+
end
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def offset=(n)
|
56
|
+
offset n
|
57
|
+
n
|
58
|
+
end
|
59
|
+
|
60
|
+
def range=(range)
|
61
|
+
@range = range
|
62
|
+
end
|
63
|
+
|
64
|
+
def begin=(n)
|
65
|
+
@range = n..range.end
|
66
|
+
end
|
67
|
+
|
68
|
+
def end=(n)
|
69
|
+
@range = range.begin..n
|
70
|
+
end
|
71
|
+
|
72
|
+
def index=(index)
|
73
|
+
@range = index..index
|
74
|
+
end
|
75
|
+
|
76
|
+
def range
|
77
|
+
@range ||= -1..-1
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def attach_pipe(end_pipe)
|
83
|
+
from = @range.begin
|
84
|
+
to = @range.end
|
85
|
+
if @range.exclude_end?
|
86
|
+
if to == 0
|
87
|
+
pipe = Pacer::Pipes::NeverPipe.new
|
88
|
+
pipe.set_starts end_pipe if end_pipe
|
89
|
+
return pipe
|
90
|
+
elsif to > 0
|
91
|
+
to -= 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
pipe = Pacer::Pipes::RangeFilterPipe.new from, to
|
95
|
+
pipe.set_starts end_pipe if end_pipe
|
96
|
+
pipe
|
97
|
+
end
|
98
|
+
|
99
|
+
def inspect_string
|
100
|
+
"#{ inspect_class_name }(#{ range.inspect })"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Routes
|
3
|
+
module RouteOperations
|
4
|
+
# Do not return duplicate elements.
|
5
|
+
def uniq(*filters, &block)
|
6
|
+
Pacer::Route.property_filter_before(self, filters, block) do |r|
|
7
|
+
chain_route :pipe_class => Pacer::Pipes::DuplicateFilterPipe, :route_name => 'uniq'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Filter
|
3
|
+
module WhereFilter
|
4
|
+
class NodeVisitor
|
5
|
+
import com.tinkerpop.pipes.filter.OrFilterPipe
|
6
|
+
import com.tinkerpop.pipes.filter.FilterPipe
|
7
|
+
import com.tinkerpop.pipes.filter.AndFilterPipe
|
8
|
+
import com.tinkerpop.pipes.filter.OrFilterPipe
|
9
|
+
import com.tinkerpop.pipes.filter.ObjectFilterPipe
|
10
|
+
import com.tinkerpop.pipes.transform.PropertyPipe
|
11
|
+
import com.tinkerpop.pipes.transform.HasCountPipe
|
12
|
+
NeverPipe = Pacer::Pipes::NeverPipe
|
13
|
+
IdentityPipe = Pacer::Pipes::IdentityPipe
|
14
|
+
PropertyComparisonFilterPipe = Pacer::Pipes::PropertyComparisonFilterPipe
|
15
|
+
Pipeline = Pacer::Pipes::Pipeline
|
16
|
+
CrossProductTransformPipe = Pacer::Pipes::CrossProductTransformPipe
|
17
|
+
UnaryTransformPipe = Pacer::Pipes::UnaryTransformPipe
|
18
|
+
BlockFilterPipe = Pacer::Pipes::BlockFilterPipe
|
19
|
+
|
20
|
+
Filters = {
|
21
|
+
'==' => FilterPipe::Filter::EQUAL,
|
22
|
+
'=' => FilterPipe::Filter::EQUAL,
|
23
|
+
'!=' => FilterPipe::Filter::NOT_EQUAL,
|
24
|
+
'>' => FilterPipe::Filter::GREATER_THAN,
|
25
|
+
'<' => FilterPipe::Filter::LESS_THAN,
|
26
|
+
'>=' => FilterPipe::Filter::GREATER_THAN_EQUAL,
|
27
|
+
'<=' => FilterPipe::Filter::LESS_THAN_EQUAL
|
28
|
+
}
|
29
|
+
|
30
|
+
ReverseFilters = Filters.merge(
|
31
|
+
'<' => FilterPipe::Filter::GREATER_THAN,
|
32
|
+
'>' => FilterPipe::Filter::LESS_THAN,
|
33
|
+
'<=' => FilterPipe::Filter::GREATER_THAN_EQUAL,
|
34
|
+
'>=' => FilterPipe::Filter::LESS_THAN_EQUAL
|
35
|
+
)
|
36
|
+
|
37
|
+
COMPARITORS = %w[ == != > < >= <= ]
|
38
|
+
METHODS = %w[ + - * / % ]
|
39
|
+
REGEX_COMPARITORS = %w[ =~ !~ ]
|
40
|
+
|
41
|
+
VALID_OPERATIONS = COMPARITORS + METHODS # + REGEX_COMPARITORS
|
42
|
+
|
43
|
+
class Pipe
|
44
|
+
def initialize(pipe, *args)
|
45
|
+
@pipe = pipe
|
46
|
+
@args = args
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_reader :pipe
|
50
|
+
attr_reader :args
|
51
|
+
|
52
|
+
def inspect(depth = 0)
|
53
|
+
([" " * depth + pipe.to_s] + args.map do |arg|
|
54
|
+
if arg.is_a? Pipe or arg.is_a? Value
|
55
|
+
arg.inspect(depth + 2)
|
56
|
+
else
|
57
|
+
" " * (depth + 2) + arg.to_s
|
58
|
+
end
|
59
|
+
end).join "\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
def build
|
63
|
+
pipe.new *build_args
|
64
|
+
end
|
65
|
+
|
66
|
+
def build_args
|
67
|
+
args.map do |arg|
|
68
|
+
if arg.is_a? Pipe
|
69
|
+
arg.build
|
70
|
+
elsif arg.is_a? Value
|
71
|
+
arg.value
|
72
|
+
else
|
73
|
+
arg
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Value
|
80
|
+
def initialize(value)
|
81
|
+
@value = value
|
82
|
+
end
|
83
|
+
|
84
|
+
def pipe; end
|
85
|
+
attr_reader :value
|
86
|
+
|
87
|
+
def inspect(depth = 0)
|
88
|
+
" " * depth + "Value: #{ value.inspect }"
|
89
|
+
end
|
90
|
+
|
91
|
+
def build
|
92
|
+
value
|
93
|
+
end
|
94
|
+
|
95
|
+
def values!
|
96
|
+
if value.is_a? Array
|
97
|
+
value.map do |v|
|
98
|
+
if v.is_a? Value
|
99
|
+
v.values!
|
100
|
+
else
|
101
|
+
raise "Arrays may not contain other properties"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
else
|
105
|
+
value
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
attr_reader :route, :values
|
111
|
+
|
112
|
+
def initialize(route, values = {})
|
113
|
+
@route = route
|
114
|
+
@values = values
|
115
|
+
end
|
116
|
+
|
117
|
+
def build_comparison(a, b, name)
|
118
|
+
# TODO: support regex matches
|
119
|
+
|
120
|
+
raise "Operation not supported: #{ name }" unless VALID_OPERATIONS.include? name
|
121
|
+
if COMPARITORS.include? name
|
122
|
+
if a.is_a? Value and b.is_a? Value
|
123
|
+
if a.value.send name, b.value
|
124
|
+
Pipe.new IdentityPipe
|
125
|
+
else
|
126
|
+
Pipe.new NeverPipe
|
127
|
+
end
|
128
|
+
elsif a.pipe == PropertyPipe and b.pipe == PropertyPipe
|
129
|
+
Pipe.new PropertyComparisonFilterPipe, a, b, Filters[name]
|
130
|
+
elsif b.pipe == PropertyPipe and a.is_a? Value
|
131
|
+
Pipe.new Pipeline, b, Pipe.new(ObjectFilterPipe, a, ReverseFilters[name])
|
132
|
+
else
|
133
|
+
Pipe.new Pipeline, a, Pipe.new(ObjectFilterPipe, b, Filters[name])
|
134
|
+
end
|
135
|
+
elsif METHODS.include? name
|
136
|
+
if a.is_a? Value and b.is_a? Value
|
137
|
+
Value.new a.value.send(name, b.value)
|
138
|
+
else
|
139
|
+
Pipe.new CrossProductTransformPipe, name, a, b
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def visitAndNode(node)
|
145
|
+
a = node.first_node.accept(self)
|
146
|
+
b = node.second_node.accept(self)
|
147
|
+
|
148
|
+
if a.pipe == AndFilterPipe and b.pipe == AndFilterPipe
|
149
|
+
Pipe.new AndFilterPipe, *a.args, *b.args
|
150
|
+
elsif a.pipe == AndFilterPipe
|
151
|
+
Pipe.new AndFilterPipe, *a.args, b
|
152
|
+
elsif b.pipe == AndFilterPipe
|
153
|
+
Pipe.new AndFilterPipe, a, *b.args
|
154
|
+
else
|
155
|
+
Pipe.new AndFilterPipe, a, b
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def visitArrayNode(node)
|
160
|
+
Value.new Value.new(node.child_nodes.map { |n| n.accept self }).values!
|
161
|
+
end
|
162
|
+
|
163
|
+
def visitBignumNode(node)
|
164
|
+
Value.new node.value.to_s
|
165
|
+
end
|
166
|
+
|
167
|
+
def visitCallNode(node)
|
168
|
+
a = node.receiver_node.accept(self)
|
169
|
+
if node.args_node
|
170
|
+
b = node.args_node.child_nodes.first.accept(self)
|
171
|
+
build_comparison(a, b, node.name)
|
172
|
+
else
|
173
|
+
return a if node.name == '+'
|
174
|
+
if a.is_a? Value
|
175
|
+
Value.new a.value.send(a.name)
|
176
|
+
elsif a.pipe == PropertyPipe
|
177
|
+
Pipe.new(UnaryTransformPipe, node.name, a)
|
178
|
+
else
|
179
|
+
case node.name
|
180
|
+
when '!'
|
181
|
+
# Special case for "a == 1 and not (b == 1)", etc.
|
182
|
+
Pipe.new(Pipeline, a, Pipe.new(HasCountPipe, -1, 0), Pipe.new(ObjectFilterPipe, true, Filters['==']))
|
183
|
+
else
|
184
|
+
raise 'not sure'
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def visitFalseNode(node)
|
191
|
+
Pipe.new NeverPipe
|
192
|
+
end
|
193
|
+
|
194
|
+
def visitFixnumNode(node)
|
195
|
+
Value.new node.value
|
196
|
+
end
|
197
|
+
|
198
|
+
def visitFloatNode(node)
|
199
|
+
Value.new node.value
|
200
|
+
end
|
201
|
+
|
202
|
+
def visitHashNode(node)
|
203
|
+
Value.new Hash[*node.child_nodes.first.accept(self).value.map { |v| v.value }]
|
204
|
+
end
|
205
|
+
|
206
|
+
def visitLocalAsgnNode(node)
|
207
|
+
a = Pipe.new PropertyPipe, node.name
|
208
|
+
b = node.value_node.accept(self)
|
209
|
+
build_comparison(a, b, '==')
|
210
|
+
end
|
211
|
+
|
212
|
+
def visitLocalVarNode(node)
|
213
|
+
Pipe.new PropertyPipe, node.name
|
214
|
+
end
|
215
|
+
|
216
|
+
def visitNewlineNode(node)
|
217
|
+
node.next_node.accept(self)
|
218
|
+
end
|
219
|
+
|
220
|
+
def visitNilNode(node)
|
221
|
+
Value.new nil
|
222
|
+
end
|
223
|
+
|
224
|
+
def visitOrNode(node)
|
225
|
+
a = node.first_node.accept(self)
|
226
|
+
b = node.second_node.accept(self)
|
227
|
+
if a.pipe == OrFilterPipe and b.pipe == OrFilterPipe
|
228
|
+
Pipe.new OrFilterPipe, *a.args, *b.args
|
229
|
+
elsif a.pipe == OrFilterPipe
|
230
|
+
Pipe.new OrFilterPipe, *a.args, b
|
231
|
+
elsif b.pipe == OrFilterPipe
|
232
|
+
Pipe.new OrFilterPipe, a, *b.args
|
233
|
+
else
|
234
|
+
Pipe.new OrFilterPipe, a, b
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def visitRootNode(node)
|
239
|
+
pipe = node.body_node.accept self
|
240
|
+
if pipe.pipe == AndFilterPipe or pipe.pipe == OrFilterPipe
|
241
|
+
pipe
|
242
|
+
elsif pipe.is_a? Value
|
243
|
+
if pipe.value
|
244
|
+
Pipe.new IdentityPipe
|
245
|
+
else
|
246
|
+
Pipe.new NeverPipe
|
247
|
+
end
|
248
|
+
else
|
249
|
+
Pipe.new AndFilterPipe, pipe
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def visitStrNode(node)
|
254
|
+
Value.new node.value
|
255
|
+
end
|
256
|
+
|
257
|
+
def visitSymbolNode(node)
|
258
|
+
Value.new values.fetch(node.name.to_sym, node.name.to_sym)
|
259
|
+
end
|
260
|
+
|
261
|
+
def visitTrueNode(node)
|
262
|
+
Pipe.new IdentityPipe
|
263
|
+
end
|
264
|
+
|
265
|
+
def visitVCallNode(node)
|
266
|
+
Pipe.new PropertyPipe, node.name
|
267
|
+
end
|
268
|
+
|
269
|
+
def visitYieldNode(node)
|
270
|
+
block = node.args_node.child_nodes.first.accept(self)
|
271
|
+
Pipe.new BlockFilterPipe, Value.new(route), block
|
272
|
+
end
|
273
|
+
|
274
|
+
def visitZArrayNode(node)
|
275
|
+
Value.new []
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pacer/filter/where_filter/node_visitor'
|
2
|
+
|
3
|
+
module Pacer
|
4
|
+
module Routes
|
5
|
+
module RouteOperations
|
6
|
+
def where(str, values = {})
|
7
|
+
chain_route :filter => :where, :where_statement => str, :values => values
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Filter
|
13
|
+
module WhereFilter
|
14
|
+
attr_reader :where_statement
|
15
|
+
attr_accessor :values
|
16
|
+
|
17
|
+
def where_statement=(str)
|
18
|
+
@where_statement = str
|
19
|
+
@built = @parsed = @intermediate = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def parsed
|
23
|
+
@parsed ||= JRuby.parse @where_statement
|
24
|
+
end
|
25
|
+
|
26
|
+
def intermediate
|
27
|
+
@intermediate ||= parsed.accept(NodeVisitor.new(self, values || {}))
|
28
|
+
end
|
29
|
+
|
30
|
+
def build!
|
31
|
+
@built ||= intermediate.build
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def attach_pipe(end_pipe)
|
37
|
+
pipe = build!
|
38
|
+
pipe.setStarts end_pipe if end_pipe
|
39
|
+
pipe
|
40
|
+
end
|
41
|
+
|
42
|
+
def inspect_string
|
43
|
+
"where(#@where_statement)"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/pacer/filter.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Filter
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'pacer/filter/collection_filter'
|
7
|
+
require 'pacer/filter/empty_filter'
|
8
|
+
require 'pacer/filter/future_filter'
|
9
|
+
require 'pacer/filter/property_filter'
|
10
|
+
require 'pacer/filter/range_filter'
|
11
|
+
require 'pacer/filter/uniq_filter'
|
12
|
+
require 'pacer/filter/index_filter'
|
13
|
+
require 'pacer/filter/loop_filter'
|
14
|
+
require 'pacer/filter/block_filter'
|
15
|
+
require 'pacer/filter/object_filter'
|
16
|
+
require 'pacer/filter/where_filter'
|
17
|
+
require 'pacer/filter/random_filter'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Pacer
|
2
|
+
module FunctionResolver
|
3
|
+
class << self
|
4
|
+
def clear_cache
|
5
|
+
@lookup_path = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def function(args)
|
9
|
+
lookup_path.each do |key, map, extension|
|
10
|
+
if value = args[key]
|
11
|
+
function = map.fetch(value, value.is_a?(Module) && value)
|
12
|
+
return [function, extension] if function
|
13
|
+
end
|
14
|
+
end
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def lookup_path
|
19
|
+
@lookup_path ||= [
|
20
|
+
[:filter, filter_map, nil],
|
21
|
+
[:transform, transform_map, nil],
|
22
|
+
[:side_effect, side_effect_map, Pacer::Core::SideEffect]
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
def filter_map
|
27
|
+
Hash[Pacer::Filter.constants.map { |name| [symbolize_module_name(name), Pacer::Filter.const_get(name)] }]
|
28
|
+
end
|
29
|
+
|
30
|
+
def side_effect_map
|
31
|
+
Hash[Pacer::SideEffect.constants.map { |name| [symbolize_module_name(name), Pacer::SideEffect.const_get(name)] }]
|
32
|
+
end
|
33
|
+
|
34
|
+
def transform_map
|
35
|
+
Hash[Pacer::Transform.constants.map { |name| [symbolize_module_name(name), Pacer::Transform.const_get(name)] }]
|
36
|
+
end
|
37
|
+
|
38
|
+
def symbolize_module_name(name)
|
39
|
+
name.to_s.sub(/(Filter|SideEffect|Transform)$/, '').gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase.to_sym
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|