pacer 0.9.1.1-java
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.
- 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
|