red_grape 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/History.txt +6 -0
- data/Manifest.txt +32 -0
- data/README.txt +59 -0
- data/Rakefile +19 -0
- data/bin/red_grape +3 -0
- data/data/graph-example-1.xml +54 -0
- data/lib/red_grape/edge.rb +34 -0
- data/lib/red_grape/graph.rb +139 -0
- data/lib/red_grape/path_group.rb +16 -0
- data/lib/red_grape/pipe/as_pipe.rb +36 -0
- data/lib/red_grape/pipe/back_pipe.rb +25 -0
- data/lib/red_grape/pipe/base.rb +83 -0
- data/lib/red_grape/pipe/context.rb +34 -0
- data/lib/red_grape/pipe/filter_pipe.rb +22 -0
- data/lib/red_grape/pipe/if_then_else_pipe.rb +27 -0
- data/lib/red_grape/pipe/in_pipe.rb +31 -0
- data/lib/red_grape/pipe/loop_pipe.rb +39 -0
- data/lib/red_grape/pipe/out_pipe.rb +37 -0
- data/lib/red_grape/pipe/paths_pipe.rb +24 -0
- data/lib/red_grape/pipe/property_pipe.rb +25 -0
- data/lib/red_grape/pipe/side_effect_pipe.rb +23 -0
- data/lib/red_grape/pipe/transform_pipe.rb +21 -0
- data/lib/red_grape/propertied_object.rb +46 -0
- data/lib/red_grape/property_description.rb +47 -0
- data/lib/red_grape/vertex.rb +46 -0
- data/lib/red_grape/vertex_group.rb +72 -0
- data/lib/red_grape.rb +31 -0
- data/test/test_graph.rb +80 -0
- data/test/test_on_the_nature_of_pipes.rb +101 -0
- data/test/test_propertied_object.rb +42 -0
- data/test/test_red_grape.rb +8 -0
- data/test/test_traversal_patterns.rb +18 -0
- data/test/test_vertex.rb +34 -0
- metadata +114 -0
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/red_grape
|
7
|
+
data/graph-example-1.xml
|
8
|
+
lib/red_grape
|
9
|
+
lib/red_grape/edge.rb
|
10
|
+
lib/red_grape/graph.rb
|
11
|
+
lib/red_grape/path_group.rb
|
12
|
+
lib/red_grape/pipe
|
13
|
+
lib/red_grape/pipe/as_pipe.rb
|
14
|
+
lib/red_grape/pipe/back_pipe.rb
|
15
|
+
lib/red_grape/pipe/base.rb
|
16
|
+
lib/red_grape/pipe/context.rb
|
17
|
+
lib/red_grape/pipe/filter_pipe.rb
|
18
|
+
lib/red_grape/pipe/if_then_else_pipe.rb
|
19
|
+
lib/red_grape/pipe/in_pipe.rb
|
20
|
+
lib/red_grape/pipe/loop_pipe.rb
|
21
|
+
lib/red_grape/pipe/out_pipe.rb
|
22
|
+
lib/red_grape/pipe/paths_pipe.rb
|
23
|
+
lib/red_grape/pipe/property_pipe.rb
|
24
|
+
lib/red_grape/pipe/side_effect_pipe.rb
|
25
|
+
lib/red_grape/pipe/transform_pipe.rb
|
26
|
+
lib/red_grape/propertied_object.rb
|
27
|
+
lib/red_grape/property_description.rb
|
28
|
+
lib/red_grape/vertex.rb
|
29
|
+
lib/red_grape/vertex_group.rb
|
30
|
+
lib/red_grape.rb
|
31
|
+
test/test_on_the_nature_of_pipes.rb
|
32
|
+
test/test_red_grape.rb
|
data/README.txt
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# RedGrape - Extremely Simple GraphDB
|
2
|
+
|
3
|
+
* https://github.com/technohippy/red-grape
|
4
|
+
|
5
|
+
## DESCRIPTION:
|
6
|
+
|
7
|
+
RedGrape is an in-memory graph database written in ruby.
|
8
|
+
|
9
|
+
## FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* load GraphML
|
12
|
+
|
13
|
+
## SYNOPSIS:
|
14
|
+
|
15
|
+
g.v(1).out('knows').filter{it.age < 30}.name.transform{it.size}
|
16
|
+
|
17
|
+
## REQUIREMENTS:
|
18
|
+
|
19
|
+
* Nokogiri (http://nokogiri.org/)
|
20
|
+
|
21
|
+
## DEVELOPERS:
|
22
|
+
|
23
|
+
After checking out the source, run:
|
24
|
+
|
25
|
+
$ rake newb
|
26
|
+
|
27
|
+
This task will install any missing dependencies, run the tests/specs,
|
28
|
+
and generate the RDoc.
|
29
|
+
|
30
|
+
## REFERENCES:
|
31
|
+
|
32
|
+
* [Tinkerpop](http://tinkerpop.com/)
|
33
|
+
** [Gremlin](https://github.com/tinkerpop/gremlin/wiki)
|
34
|
+
** [Pipes](https://github.com/tinkerpop/pipes/wiki/)
|
35
|
+
|
36
|
+
## LICENSE:
|
37
|
+
|
38
|
+
(The MIT License)
|
39
|
+
|
40
|
+
Copyright (c) 2012 ANDO Yasushi
|
41
|
+
|
42
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
43
|
+
a copy of this software and associated documentation files (the
|
44
|
+
'Software'), to deal in the Software without restriction, including
|
45
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
46
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
47
|
+
permit persons to whom the Software is furnished to do so, subject to
|
48
|
+
the following conditions:
|
49
|
+
|
50
|
+
The above copyright notice and this permission notice shall be
|
51
|
+
included in all copies or substantial portions of the Software.
|
52
|
+
|
53
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
54
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
55
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
56
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
57
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
58
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
59
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
|
6
|
+
# Hoe.plugin :compiler
|
7
|
+
# Hoe.plugin :gem_prelude_sucks
|
8
|
+
# Hoe.plugin :inline
|
9
|
+
# Hoe.plugin :racc
|
10
|
+
# Hoe.plugin :rcov
|
11
|
+
# Hoe.plugin :rubyforge
|
12
|
+
|
13
|
+
Hoe.spec 'red_grape' do
|
14
|
+
developer('ANDO Yasushi', 'andyjpn@gmail.com')
|
15
|
+
|
16
|
+
# self.rubyforge_name = 'red_grapex' # if different than 'red_grape'
|
17
|
+
end
|
18
|
+
|
19
|
+
# vim: syntax=ruby
|
data/bin/red_grape
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
|
5
|
+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
|
6
|
+
<key id="weight" for="edge" attr.name="weight" attr.type="float"/>
|
7
|
+
<key id="name" for="node" attr.name="name" attr.type="string"/>
|
8
|
+
<key id="age" for="node" attr.name="age" attr.type="int"/>
|
9
|
+
<key id="lang" for="node" attr.name="lang" attr.type="string"/>
|
10
|
+
<graph id="G" edgedefault="directed">
|
11
|
+
<node id="1">
|
12
|
+
<data key="name">marko</data>
|
13
|
+
<data key="age">29</data>
|
14
|
+
</node>
|
15
|
+
<node id="2">
|
16
|
+
<data key="name">vadas</data>
|
17
|
+
<data key="age">27</data>
|
18
|
+
</node>
|
19
|
+
<node id="3">
|
20
|
+
<data key="name">lop</data>
|
21
|
+
<data key="lang">java</data>
|
22
|
+
</node>
|
23
|
+
<node id="4">
|
24
|
+
<data key="name">josh</data>
|
25
|
+
<data key="age">32</data>
|
26
|
+
</node>
|
27
|
+
<node id="5">
|
28
|
+
<data key="name">ripple</data>
|
29
|
+
<data key="lang">java</data>
|
30
|
+
</node>
|
31
|
+
<node id="6">
|
32
|
+
<data key="name">peter</data>
|
33
|
+
<data key="age">35</data>
|
34
|
+
</node>
|
35
|
+
<edge id="7" source="1" target="2" label="knows">
|
36
|
+
<data key="weight">0.5</data>
|
37
|
+
</edge>
|
38
|
+
<edge id="8" source="1" target="4" label="knows">
|
39
|
+
<data key="weight">1.0</data>
|
40
|
+
</edge>
|
41
|
+
<edge id="9" source="1" target="3" label="created">
|
42
|
+
<data key="weight">0.4</data>
|
43
|
+
</edge>
|
44
|
+
<edge id="10" source="4" target="5" label="created">
|
45
|
+
<data key="weight">1.0</data>
|
46
|
+
</edge>
|
47
|
+
<edge id="11" source="4" target="3" label="created">
|
48
|
+
<data key="weight">0.4</data>
|
49
|
+
</edge>
|
50
|
+
<edge id="12" source="6" target="3" label="created">
|
51
|
+
<data key="weight">0.2</data>
|
52
|
+
</edge>
|
53
|
+
</graph>
|
54
|
+
</graphml>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'red_grape/propertied_object'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
class Edge < PropertiedObject
|
5
|
+
attr_reader :source, :target, :label
|
6
|
+
|
7
|
+
def initialize(graph, id, source, target, label, opts={})
|
8
|
+
super graph, opts
|
9
|
+
@id = id
|
10
|
+
@source = source.is_a?(Vertex) ? source : graph.vertex(source)
|
11
|
+
@target = target.is_a?(Vertex) ? target : graph.vertex(target)
|
12
|
+
@source.add_out_edge self
|
13
|
+
@target.add_in_edge self
|
14
|
+
@label = label
|
15
|
+
end
|
16
|
+
|
17
|
+
def _id
|
18
|
+
@id
|
19
|
+
end
|
20
|
+
|
21
|
+
def _source
|
22
|
+
@source
|
23
|
+
end
|
24
|
+
|
25
|
+
def _target
|
26
|
+
@target
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
#"e[id(#{_id}):v[#{@source._id}]-v[#{@target._id}]:#{@property}]"
|
31
|
+
"e[#{_id}:v[#{@source._id}]-v[#{@target._id}]]"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'red_grape/vertex'
|
3
|
+
require 'red_grape/vertex_group'
|
4
|
+
require 'red_grape/edge'
|
5
|
+
require 'red_grape/edge_group'
|
6
|
+
require 'red_grape/property_description'
|
7
|
+
|
8
|
+
module RedGrape
|
9
|
+
class Graph
|
10
|
+
# TODO: https://github.com/tinkerpop/blueprints/blob/bed2e64010882be66bf3b46d3c3e4b4ef4f6f2d9/blueprints-core/src/main/java/com/tinkerpop/blueprints/pgm/impls/tg/TinkerGraphFactory.java
|
11
|
+
NAMESPACES = {
|
12
|
+
'xmlns' => 'http://graphml.graphdrawing.org/xmlns',
|
13
|
+
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
14
|
+
}
|
15
|
+
|
16
|
+
class <<self
|
17
|
+
def load(filename)
|
18
|
+
if filename =~ /^<\?xml/
|
19
|
+
self.new.load StringIO.new(filename)
|
20
|
+
else
|
21
|
+
self.new.load filename
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@vertices = {}
|
28
|
+
@edges = {}
|
29
|
+
@property_descriptions = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def vertex(*id)
|
33
|
+
if 1 < id.size
|
34
|
+
VertexGroup.new(id.map{|i| @vertices[i.to_s]})
|
35
|
+
elsif id.size == 0
|
36
|
+
VertexGroup.new @vertices.values
|
37
|
+
else
|
38
|
+
case id.first
|
39
|
+
when Array
|
40
|
+
VertexGroup.new(id.first.map{|i| @vertices[i.to_s]})
|
41
|
+
when :all
|
42
|
+
VertexGroup.new @vertices.values
|
43
|
+
else
|
44
|
+
@vertices[id.first.to_s]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
alias v vertex
|
49
|
+
alias V vertex
|
50
|
+
|
51
|
+
def edge(id)
|
52
|
+
@edges[id.to_s]
|
53
|
+
end
|
54
|
+
alias e edge
|
55
|
+
|
56
|
+
def add_vertex(id, v=nil)
|
57
|
+
if v
|
58
|
+
if v.is_a? Hash
|
59
|
+
v = Vertex.new self, id, v
|
60
|
+
end
|
61
|
+
else
|
62
|
+
if id.is_a? Hash
|
63
|
+
v = id
|
64
|
+
id = v[:id] || v['id']
|
65
|
+
else
|
66
|
+
v = id
|
67
|
+
id = v._id
|
68
|
+
end
|
69
|
+
v = Vertex.new self, id, v
|
70
|
+
end
|
71
|
+
raise ArgumentError.new 'invalid id' unless id == v._id
|
72
|
+
|
73
|
+
@vertices[id.to_s] = v
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_edge(id, label, from, to)
|
77
|
+
edge = if id.is_a? Edge
|
78
|
+
id
|
79
|
+
else
|
80
|
+
id = id.to_s
|
81
|
+
from = self.vertex[from.to_s] unless from.is_a? Vertex
|
82
|
+
to = self.vertex[to.to_s] unless to.is_a? Vertex
|
83
|
+
add_vertex from unless self.vertex(from._id)
|
84
|
+
add_vertex to unless self.vertex(to._id)
|
85
|
+
Edge.new self, id, from, to, label
|
86
|
+
end
|
87
|
+
@edges[edge._id] = edge
|
88
|
+
end
|
89
|
+
|
90
|
+
def load(file, type=:xml)
|
91
|
+
file = File.open file if file.is_a? String
|
92
|
+
case type
|
93
|
+
when :xml
|
94
|
+
parse_xml Nokogiri::XML(file)
|
95
|
+
end
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
# assumption: any sub-graph does not exist.
|
100
|
+
def parse_xml(xml)
|
101
|
+
nodes(xml, 'key').each do |key_elm|
|
102
|
+
defaults = nodes key_elm, 'default'
|
103
|
+
default = defaults.size == 0 ? nil : defaults.first.children.to_s
|
104
|
+
prop = PropertyDescription.new key_elm['attr.name'], key_elm['attr.type'], default
|
105
|
+
(@property_descriptions[key_elm['for']] ||= {})[key_elm['id']] = prop
|
106
|
+
end
|
107
|
+
nodes(xml, 'node').each do |node_elm|
|
108
|
+
vertex = Vertex.new self, node_elm['id'],
|
109
|
+
:property_description => @property_descriptions['node']
|
110
|
+
data = nodes node_elm, 'data'
|
111
|
+
data.each do |data_elm|
|
112
|
+
vertex.set_property data_elm['key'], data_elm.children.first.to_s
|
113
|
+
end
|
114
|
+
@vertices[vertex._id] = vertex
|
115
|
+
end
|
116
|
+
nodes(xml, 'edge').each do |edge_elm|
|
117
|
+
edge = Edge.new self, edge_elm['id'], edge_elm['source'], edge_elm['target'],
|
118
|
+
edge_elm['label'], :property_description => @property_descriptions['edge']
|
119
|
+
data = nodes edge_elm, 'data'
|
120
|
+
data.each do |data_elm|
|
121
|
+
edge.set_property data_elm['key'], data_elm.children.first.to_s
|
122
|
+
end
|
123
|
+
@edges[edge._id] = edge
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def find(*args)
|
128
|
+
Graph::Vertex.new
|
129
|
+
end
|
130
|
+
|
131
|
+
def nodes(xml, elm)
|
132
|
+
xml.xpath(".//xmlns:#{elm}", NAMESPACES)
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_s
|
136
|
+
{:vertices => @vertices, :edges => @edges}.to_s
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
module As
|
6
|
+
def as(*opts)
|
7
|
+
AsPipe.new self, *opts
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class AsPipe < Pipe::Base
|
12
|
+
def pass(obj, context)
|
13
|
+
label = self.opts.first.to_s
|
14
|
+
case self.prev
|
15
|
+
when Pipe::Base
|
16
|
+
# TODO: why??
|
17
|
+
context.mark! label
|
18
|
+
obj
|
19
|
+
when Vertex
|
20
|
+
if self.last?
|
21
|
+
context.mark! label
|
22
|
+
obj
|
23
|
+
else
|
24
|
+
context.push_history obj do |ctx|
|
25
|
+
context.mark! label
|
26
|
+
obj.pass_through self.next, ctx
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
raise 'not yet'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class BackPipe < Pipe::Base
|
6
|
+
def pass(obj, context)
|
7
|
+
label = self.opts.first
|
8
|
+
obj = case label
|
9
|
+
when Integer
|
10
|
+
context.history[-label]
|
11
|
+
else
|
12
|
+
context.mark label
|
13
|
+
end
|
14
|
+
|
15
|
+
if self.last?
|
16
|
+
obj
|
17
|
+
else
|
18
|
+
context.push_history obj do |ctx|
|
19
|
+
obj.pass_through self.next, ctx
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'red_grape/pipe/context'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class Base
|
6
|
+
attr_accessor :opts, :prev, :next, :value
|
7
|
+
|
8
|
+
def initialize(prev, *opts, &block)
|
9
|
+
@prev = prev
|
10
|
+
@next = nil
|
11
|
+
@opts = opts
|
12
|
+
@block = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def pipe_name
|
16
|
+
self.class.name.split('::').last
|
17
|
+
end
|
18
|
+
|
19
|
+
def first?
|
20
|
+
not @prev.kind_of? RedGrape::Pipe::Base
|
21
|
+
end
|
22
|
+
|
23
|
+
def last?
|
24
|
+
@next.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def done?
|
28
|
+
not @value.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def take
|
32
|
+
if first?
|
33
|
+
@prev.pass_through self, Pipe::Context.new
|
34
|
+
else
|
35
|
+
@prev.take
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
#TODO: flag
|
41
|
+
take.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_a
|
45
|
+
pipe = self
|
46
|
+
ret = [pipe.pipe_name]
|
47
|
+
until pipe.first?
|
48
|
+
pipe = pipe.prev
|
49
|
+
ret.unshift pipe.pipe_name
|
50
|
+
end
|
51
|
+
ret
|
52
|
+
end
|
53
|
+
|
54
|
+
def size
|
55
|
+
len = 0
|
56
|
+
pipe = self
|
57
|
+
while pipe.is_a?(RedGrape::Pipe::Base) and pipe.prev
|
58
|
+
len += 1
|
59
|
+
pipe = pipe.prev
|
60
|
+
end
|
61
|
+
len
|
62
|
+
end
|
63
|
+
|
64
|
+
# note: both prev and next are not copied.
|
65
|
+
def dup
|
66
|
+
self.class.new nil, @opts, &@block
|
67
|
+
end
|
68
|
+
|
69
|
+
def method_missing(name, *args, &block)
|
70
|
+
class_name = "#{name.to_s.sub(/^./){$&.upcase}.gsub(/_(.)/){$1.upcase}}Pipe"
|
71
|
+
args.unshift block if block
|
72
|
+
pipe_class =
|
73
|
+
if RedGrape::Pipe.const_defined? class_name
|
74
|
+
eval "RedGrape::Pipe::#{class_name}"
|
75
|
+
else
|
76
|
+
args.unshift name
|
77
|
+
RedGrape::Pipe::PropertyPipe
|
78
|
+
end
|
79
|
+
@next = pipe_class.new self, *args
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RedGrape
|
2
|
+
module Pipe
|
3
|
+
class Context
|
4
|
+
attr_accessor :it, :loops
|
5
|
+
attr_reader :history
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@history = []
|
9
|
+
@marks = {}
|
10
|
+
@loops = 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def push_history(obj, &block)
|
14
|
+
@history.push obj
|
15
|
+
ret = block.call self
|
16
|
+
@history.pop
|
17
|
+
ret
|
18
|
+
end
|
19
|
+
|
20
|
+
def mark!(label)
|
21
|
+
@marks[label] = @history.last
|
22
|
+
end
|
23
|
+
|
24
|
+
def mark(label)
|
25
|
+
@marks[label]
|
26
|
+
end
|
27
|
+
|
28
|
+
def eval(args={}, &block)
|
29
|
+
args.each {|k, v| self.send "#{k}=", v}
|
30
|
+
instance_eval(&block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class FilterPipe < Pipe::Base
|
6
|
+
def pass(obj, context)
|
7
|
+
filter = self.opts.first
|
8
|
+
if context.eval :it => obj, &filter
|
9
|
+
if self.last?
|
10
|
+
obj
|
11
|
+
else
|
12
|
+
context.push_history obj do |ctx|
|
13
|
+
obj.pass_through self.next, ctx
|
14
|
+
end
|
15
|
+
end
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class IfThenElsePipe < Pipe::Base
|
6
|
+
def pass(obj, context)
|
7
|
+
condition = self.opts[0]
|
8
|
+
then_block = self.opts[1]
|
9
|
+
else_block = self.opts[2]
|
10
|
+
ret =
|
11
|
+
if context.eval({:it => obj}, &condition)
|
12
|
+
context.eval({:it => obj}, &then_block)
|
13
|
+
else
|
14
|
+
context.eval({:it => obj}, &else_block)
|
15
|
+
end
|
16
|
+
ret = ret.take if ret.is_a? Pipe::Base
|
17
|
+
if self.last?
|
18
|
+
ret
|
19
|
+
else
|
20
|
+
context.push_history ret do |ctx|
|
21
|
+
ret.pass_through self.next, ctx
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'red_grape/pipe/base'
|
2
|
+
|
3
|
+
module RedGrape
|
4
|
+
module Pipe
|
5
|
+
class InPipe < Pipe::Base
|
6
|
+
def pipe_name
|
7
|
+
@opts.empty? ? super : "#{super}(#{@opts.first})"
|
8
|
+
end
|
9
|
+
|
10
|
+
def pass(obj, context)
|
11
|
+
case obj
|
12
|
+
when RedGrape::Vertex
|
13
|
+
group =
|
14
|
+
if self.opts.empty?
|
15
|
+
VertexGroup.new obj._in_edges.map(&:source)
|
16
|
+
else
|
17
|
+
label = self.opts.first
|
18
|
+
VertexGroup.new obj._in_edges.find_all{|e| e.label == label}.map(&:source)
|
19
|
+
end
|
20
|
+
if self.last?
|
21
|
+
group
|
22
|
+
else
|
23
|
+
context.push_history obj do |ctx|
|
24
|
+
group.pass_through self.next, ctx
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|