red_grape 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ext/array_ext.rb +11 -5
- data/lib/red_grape/pipe/base.rb +2 -0
- data/lib/red_grape/pipe/cap_pipe.rb +3 -3
- data/lib/red_grape/pipe/context.rb +32 -5
- data/lib/red_grape/pipe/gather_pipe.rb +12 -0
- data/lib/red_grape/pipe/group_by_pipe.rb +29 -0
- data/lib/red_grape/pipe/group_count_pipe.rb +4 -4
- data/lib/red_grape/pipe/has_not_pipe.rb +19 -0
- data/lib/red_grape/pipe/scatter_pipe.rb +13 -0
- data/lib/red_grape/pipe/underscore_pipe.rb +6 -2
- data/lib/red_grape.rb +6 -3
- data/test/test_traversal_patterns.rb +36 -6
- metadata +8 -5
- data/lib/red_grape/version.rb +0 -3
data/lib/ext/array_ext.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
class Array
|
2
|
+
attr_accessor :should_pass_through_whole #TODO
|
3
|
+
|
2
4
|
def pass_through(pipe, context)
|
3
|
-
|
4
|
-
|
5
|
+
if @should_pass_through_whole
|
6
|
+
super
|
7
|
+
else
|
8
|
+
loops = context.loops
|
9
|
+
map! do |e|
|
10
|
+
context.loops = loops
|
11
|
+
pipe.pass e, context
|
12
|
+
end
|
5
13
|
context.loops = loops
|
6
|
-
|
14
|
+
normalize_for_graph
|
7
15
|
end
|
8
|
-
context.loops = loops
|
9
|
-
normalize_for_graph
|
10
16
|
end
|
11
17
|
|
12
18
|
def normalize_for_graph
|
data/lib/red_grape/pipe/base.rb
CHANGED
@@ -5,9 +5,9 @@ module RedGrape
|
|
5
5
|
class CapPipe < Pipe::Base
|
6
6
|
def pass(obj, context)
|
7
7
|
ret = {}
|
8
|
-
context.grouping_items.each do |
|
9
|
-
|
10
|
-
ret[
|
8
|
+
context.grouping_items.each do |k, v|
|
9
|
+
v = v.map &:first
|
10
|
+
ret[k] = self.pipe_eval(it:v, &self.prev.reduce_function)
|
11
11
|
end
|
12
12
|
ret
|
13
13
|
end
|
@@ -9,7 +9,8 @@ module RedGrape
|
|
9
9
|
@marks = {}
|
10
10
|
@aggregating_items = {}
|
11
11
|
@aggregated_items = {}
|
12
|
-
@grouping_items =
|
12
|
+
@grouping_items = {}
|
13
|
+
@gathering_items = []
|
13
14
|
@loops = 1
|
14
15
|
end
|
15
16
|
|
@@ -66,8 +67,8 @@ module RedGrape
|
|
66
67
|
ret.normalize_for_graph
|
67
68
|
end
|
68
69
|
|
69
|
-
def group(
|
70
|
-
@grouping_items << [val, next_pipe]
|
70
|
+
def group(next_pipe, key, val=key)
|
71
|
+
(@grouping_items[key] ||= []) << [val, next_pipe]
|
71
72
|
val
|
72
73
|
end
|
73
74
|
|
@@ -76,16 +77,42 @@ module RedGrape
|
|
76
77
|
end
|
77
78
|
|
78
79
|
def resume_from_grouping
|
79
|
-
obj, pipe = *@grouping_items.first # TODO: '.first' is used to get next_pipe.
|
80
|
+
obj, pipe = *@grouping_items.values.first.first # TODO: '.first' is used to get next_pipe.
|
80
81
|
if pipe
|
81
82
|
push_history obj do |ctx|
|
82
|
-
obj.pass_through
|
83
|
+
obj.pass_through pipe, ctx
|
83
84
|
end
|
84
85
|
else
|
85
86
|
obj
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
90
|
+
def gather(obj, next_pipe)
|
91
|
+
@gathering_items << [obj, next_pipe]
|
92
|
+
end
|
93
|
+
|
94
|
+
def gathering?
|
95
|
+
not @gathering_items.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
def clear_gathering
|
99
|
+
@gathering_items.clear
|
100
|
+
end
|
101
|
+
|
102
|
+
def resume_from_gathering
|
103
|
+
obj, pipe = *@gathering_items.first
|
104
|
+
objs = @gathering_items.map &:first
|
105
|
+
objs.should_pass_through_whole = true
|
106
|
+
if pipe
|
107
|
+
push_history objs do |ctx|
|
108
|
+
pipe.prev = objs
|
109
|
+
pipe.take ctx
|
110
|
+
end
|
111
|
+
else
|
112
|
+
objs
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
89
116
|
def eval(args={}, &block)
|
90
117
|
args.each {|k, v| self.send "#{k}=", v}
|
91
118
|
instance_eval(&block)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class GroupByPipe < Pipe::Base
|
6
|
+
attr_accessor :reduce_function
|
7
|
+
|
8
|
+
def pass(obj, context)
|
9
|
+
key_function, value_function, @reduce_function = *self.opts
|
10
|
+
value_function ||= proc{it}
|
11
|
+
@reduce_function ||= proc{it}
|
12
|
+
if self.opts.empty?
|
13
|
+
context.group self.next, obj
|
14
|
+
elsif self.opts.first.is_a? Proc
|
15
|
+
context.group(
|
16
|
+
self.next,
|
17
|
+
pipe_eval(it:obj, &key_function),
|
18
|
+
pipe_eval(it:obj, &value_function)
|
19
|
+
)
|
20
|
+
else
|
21
|
+
self.opts.first[obj] ||= []
|
22
|
+
self.opts.first[obj] << obj
|
23
|
+
end
|
24
|
+
obj
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -3,13 +3,13 @@ require 'red_grape/pipe/base'
|
|
3
3
|
module RedGrape
|
4
4
|
module Pipe
|
5
5
|
class GroupCountPipe < Pipe::Base
|
6
|
+
attr_accessor :reduce_function
|
6
7
|
def pass(obj, context)
|
8
|
+
@reduce_function = proc{it.size}
|
7
9
|
if self.opts.empty?
|
8
|
-
|
9
|
-
context.group obj, self.next
|
10
|
+
context.group self.next, obj
|
10
11
|
elsif self.opts.first.is_a? Proc
|
11
|
-
|
12
|
-
context.group pipe_eval(it:obj, &self.opts.first), self.next
|
12
|
+
context.group self.next, pipe_eval(it:obj, &self.opts.first)
|
13
13
|
else
|
14
14
|
self.opts.first[obj] ||= 0
|
15
15
|
self.opts.first[obj] += 1
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class HasNotPipe < Pipe::Base
|
6
|
+
def pass(obj, context)
|
7
|
+
prop, val = *self.opts
|
8
|
+
filter = proc{it[prop] == val}
|
9
|
+
|
10
|
+
# TODO: same as filter_pipe (has_pipe)
|
11
|
+
unless context.eval :it => obj, &filter
|
12
|
+
pass_next context, obj
|
13
|
+
else
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -3,8 +3,12 @@ require 'red_grape/pipe/base'
|
|
3
3
|
module RedGrape
|
4
4
|
module Pipe
|
5
5
|
module Underscore
|
6
|
-
def _(*opts)
|
7
|
-
|
6
|
+
def _(*opts, &block)
|
7
|
+
if block
|
8
|
+
Proc.new &block
|
9
|
+
else
|
10
|
+
UnderscorePipe.new self.dup, *opts#
|
11
|
+
end
|
8
12
|
end
|
9
13
|
end
|
10
14
|
|
data/lib/red_grape.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
module RedGrape
|
2
|
+
VERSION = '0.0.10'
|
3
|
+
end
|
4
|
+
|
1
5
|
require 'ext/nil_class_ext'
|
2
6
|
require 'ext/object_ext'
|
3
7
|
require 'ext/array_ext'
|
4
|
-
require 'red_grape/version'
|
5
8
|
require 'red_grape/pipe/aggregate_pipe'
|
6
9
|
require 'red_grape/pipe/as_pipe'
|
7
10
|
require 'red_grape/pipe/back_pipe'
|
@@ -11,6 +14,7 @@ require 'red_grape/pipe/except_pipe'
|
|
11
14
|
require 'red_grape/pipe/exhaust_merge_pipe'
|
12
15
|
require 'red_grape/pipe/fill_pipe'
|
13
16
|
require 'red_grape/pipe/filter_pipe'
|
17
|
+
require 'red_grape/pipe/gather_pipe'
|
14
18
|
require 'red_grape/pipe/group_by_pipe'
|
15
19
|
require 'red_grape/pipe/group_count_pipe'
|
16
20
|
require 'red_grape/pipe/has_pipe'
|
@@ -26,6 +30,7 @@ require 'red_grape/pipe/out_v_pipe'
|
|
26
30
|
require 'red_grape/pipe/property_pipe'
|
27
31
|
require 'red_grape/pipe/paths_pipe'
|
28
32
|
require 'red_grape/pipe/retain_pipe'
|
33
|
+
require 'red_grape/pipe/scatter_pipe'
|
29
34
|
require 'red_grape/pipe/side_effect_pipe'
|
30
35
|
require 'red_grape/pipe/transform_pipe'
|
31
36
|
require 'red_grape/pipe/v_pipe'
|
@@ -33,8 +38,6 @@ require 'red_grape/pipe/e_pipe'
|
|
33
38
|
require 'red_grape/graph'
|
34
39
|
|
35
40
|
module RedGrape
|
36
|
-
VERSION = "0.0.9"
|
37
|
-
|
38
41
|
module_function
|
39
42
|
def set_auto_take(val=true)
|
40
43
|
Pipe.set_auto_take val
|
@@ -117,17 +117,47 @@ class TraversalPatternsTest < Test::Unit::TestCase
|
|
117
117
|
)
|
118
118
|
end
|
119
119
|
|
120
|
+
# https://github.com/tinkerpop/gremlin/wiki/MapReduce-Pattern
|
120
121
|
def test_map_reduce_pattern
|
121
122
|
@g2 ||= RedGrape.load_graph 'data/graph-example-2.xml'
|
122
123
|
assert_equal(
|
123
124
|
{'cover'=>313, 'original'=>184},
|
124
125
|
@g2.V.has_not('song_type', nil).group_count(proc{it.song_type}).cap.take
|
125
126
|
)
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
|
128
|
+
ret = @g2.V.has_not('song_type', nil).group_by(proc{it.song_type}, proc{it}).cap.take
|
129
|
+
assert_equal 2, ret.keys.size
|
130
|
+
assert_equal 313, ret.values[0].size
|
131
|
+
assert ret.values[0].all?{|e| e.is_a? RedGrape::Vertex}
|
132
|
+
assert_equal 184, ret.values[1].size
|
133
|
+
assert ret.values[1].all?{|e| e.is_a? RedGrape::Vertex}
|
134
|
+
|
135
|
+
ret = @g2.V.has_not('song_type', nil).group_by(_{it.song_type}, _{it.name}).cap.take
|
136
|
+
assert_equal 2, ret.keys.size
|
137
|
+
assert_equal 313, ret.values[0].size
|
138
|
+
assert ret.values[0].all?{|e| e.is_a? String}
|
139
|
+
assert_equal 184, ret.values[1].size
|
140
|
+
assert ret.values[1].all?{|e| e.is_a? String}
|
141
|
+
assert_equal 'HEY BO DIDDLEY', ret.values[0][0]
|
142
|
+
assert_equal 'BERTHA', ret.values[1][0]
|
143
|
+
|
144
|
+
ret = @g2.V.has_not('song_type', nil).group_by(_{it.song_type}, _{1}).cap.take
|
145
|
+
assert_equal 2, ret.keys.size
|
146
|
+
assert ret.values[0].all?{|e| e == 1}
|
147
|
+
assert ret.values[1].all?{|e| e == 1}
|
148
|
+
|
149
|
+
ret = @g2.V.has_not('song_type', nil).group_by(_{it.song_type}, _{1}, _{it.size}).cap.take
|
150
|
+
assert_equal 313, ret.values[0]
|
151
|
+
assert_equal 184, ret.values[1]
|
152
|
+
|
153
|
+
ret = @g2.V.has_not('song_type', nil).group_by(_{it.song_type}, _{it.out('sung_by').take}, _{it._.name.group_count.cap.take}).cap.take
|
154
|
+
assert_equal 66, ret[0]['cover']['Weir']
|
155
|
+
assert_equal 33, ret[0]['original']['Weir']
|
156
|
+
end
|
157
|
+
|
158
|
+
# https://github.com/tinkerpop/gremlin/wiki/Depth-First-vs.-Breadth-First
|
159
|
+
def test_depth_first_vs_bredth_first
|
160
|
+
assert_equal %w(1 4 6), @g1.v(1).out_e('created').in_v.in_e('created').out_v.take.map(&:id)
|
161
|
+
assert_equal %w(1 4 6), @g1.v(1).out_e('created').gather.scatter.in_v.gather.scatter.in_e('created').gather.scatter.out_v.gather.scatter.take.map(&:id)
|
132
162
|
end
|
133
163
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: red_grape
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
|
-
requirement: &
|
16
|
+
requirement: &70324009053140 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70324009053140
|
25
25
|
description: RedGrape is an in-memory graph database written in ruby. I made this
|
26
26
|
in order to learn how graph databases work so that please do not use this for any
|
27
27
|
serious purpose.
|
@@ -61,7 +61,10 @@ files:
|
|
61
61
|
- lib/red_grape/pipe/exhaust_merge_pipe.rb
|
62
62
|
- lib/red_grape/pipe/fill_pipe.rb
|
63
63
|
- lib/red_grape/pipe/filter_pipe.rb
|
64
|
+
- lib/red_grape/pipe/gather_pipe.rb
|
65
|
+
- lib/red_grape/pipe/group_by_pipe.rb
|
64
66
|
- lib/red_grape/pipe/group_count_pipe.rb
|
67
|
+
- lib/red_grape/pipe/has_not_pipe.rb
|
65
68
|
- lib/red_grape/pipe/has_pipe.rb
|
66
69
|
- lib/red_grape/pipe/if_then_else_pipe.rb
|
67
70
|
- lib/red_grape/pipe/in_e_pipe.rb
|
@@ -74,6 +77,7 @@ files:
|
|
74
77
|
- lib/red_grape/pipe/paths_pipe.rb
|
75
78
|
- lib/red_grape/pipe/property_pipe.rb
|
76
79
|
- lib/red_grape/pipe/retain_pipe.rb
|
80
|
+
- lib/red_grape/pipe/scatter_pipe.rb
|
77
81
|
- lib/red_grape/pipe/side_effect_pipe.rb
|
78
82
|
- lib/red_grape/pipe/transform_pipe.rb
|
79
83
|
- lib/red_grape/pipe/underscore_pipe.rb
|
@@ -82,7 +86,6 @@ files:
|
|
82
86
|
- lib/red_grape/serializer/graphml_serializer.rb
|
83
87
|
- lib/red_grape/tools/graph_store.rb
|
84
88
|
- lib/red_grape/tools/irg.rb
|
85
|
-
- lib/red_grape/version.rb
|
86
89
|
- lib/red_grape/vertex.rb
|
87
90
|
- red_grape.gemspec
|
88
91
|
- test/all.rb
|
data/lib/red_grape/version.rb
DELETED