red_grape 0.0.1 → 0.0.2

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.
Files changed (45) hide show
  1. data/Manifest.txt +25 -10
  2. data/README.txt +54 -5
  3. data/bin/redgrape +77 -0
  4. data/data/graph-example-2.xml +26380 -0
  5. data/lib/ext/array_ext.rb +41 -0
  6. data/lib/ext/object_ext.rb +16 -0
  7. data/lib/red_grape/edge.rb +4 -17
  8. data/lib/red_grape/{propertied_object.rb → element.rb} +26 -4
  9. data/lib/red_grape/graph.rb +75 -73
  10. data/lib/red_grape/path_group.rb +5 -9
  11. data/lib/red_grape/pipe/aggregate_pipe.rb +13 -0
  12. data/lib/red_grape/pipe/as_pipe.rb +3 -10
  13. data/lib/red_grape/pipe/back_pipe.rb +1 -8
  14. data/lib/red_grape/pipe/base.rb +51 -6
  15. data/lib/red_grape/pipe/cap_pipe.rb +16 -0
  16. data/lib/red_grape/pipe/context.rb +64 -3
  17. data/lib/red_grape/pipe/except_pipe.rb +15 -0
  18. data/lib/red_grape/pipe/fill_pipe.rb +19 -0
  19. data/lib/red_grape/pipe/filter_pipe.rb +1 -7
  20. data/lib/red_grape/pipe/group_count_pipe.rb +17 -0
  21. data/lib/red_grape/pipe/has_pipe.rb +24 -0
  22. data/lib/red_grape/pipe/if_then_else_pipe.rb +1 -7
  23. data/lib/red_grape/pipe/in_pipe.rb +12 -15
  24. data/lib/red_grape/pipe/in_v_pipe.rb +12 -0
  25. data/lib/red_grape/pipe/loop_pipe.rb +16 -25
  26. data/lib/red_grape/pipe/out_e_pipe.rb +25 -0
  27. data/lib/red_grape/pipe/out_pipe.rb +6 -15
  28. data/lib/red_grape/pipe/paths_pipe.rb +21 -9
  29. data/lib/red_grape/pipe/property_pipe.rb +2 -11
  30. data/lib/red_grape/pipe/retain_pipe.rb +16 -0
  31. data/lib/red_grape/pipe/transform_pipe.rb +3 -11
  32. data/lib/red_grape/property_description.rb +6 -0
  33. data/lib/red_grape/serializer/graphml_serializer.rb +73 -0
  34. data/lib/red_grape/vertex.rb +7 -20
  35. data/lib/red_grape.rb +15 -6
  36. data/test/{test_propertied_object.rb → test_element.rb} +5 -5
  37. data/test/test_graph.rb +10 -19
  38. data/test/test_on_the_nature_of_pipes.rb +13 -13
  39. data/test/test_pipe.rb +16 -0
  40. data/test/test_pipe_base.rb +17 -0
  41. data/test/test_traversal_patterns.rb +69 -0
  42. metadata +38 -22
  43. data/bin/red_grape +0 -3
  44. data/lib/red_grape/vertex_group.rb +0 -72
  45. data/test/test_red_grape.rb +0 -8
@@ -6,13 +6,7 @@ module RedGrape
6
6
  def pass(obj, context)
7
7
  filter = self.opts.first
8
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
9
+ pass_next context, obj
16
10
  else
17
11
  nil
18
12
  end
@@ -0,0 +1,17 @@
1
+ require 'red_grape/pipe/base'
2
+
3
+ module RedGrape
4
+ module Pipe
5
+ class GroupCountPipe < Pipe::Base
6
+ def pass(obj, context)
7
+ if self.opts.empty?
8
+ context.group obj, self.next
9
+ else
10
+ self.opts.first[obj] ||= 0
11
+ self.opts.first[obj] += 1
12
+ end
13
+ obj
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ require 'red_grape/pipe/base'
2
+
3
+ module RedGrape
4
+ module Pipe
5
+ class HasPipe < Pipe::Base
6
+ def pass(obj, context)
7
+ prop, cond, val = *self.opts
8
+ cond = case cond
9
+ when :gt; :>
10
+ when :lt; :<
11
+ else; cond
12
+ end
13
+ filter = proc{it[prop].send(cond, val)}
14
+
15
+ # TODO: same as filter_pipe
16
+ if context.eval :it => obj, &filter
17
+ pass_next context, obj
18
+ else
19
+ nil
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -14,13 +14,7 @@ module RedGrape
14
14
  context.eval({:it => obj}, &else_block)
15
15
  end
16
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
17
+ pass_next context, ret
24
18
  end
25
19
  end
26
20
  end
@@ -2,29 +2,26 @@ require 'red_grape/pipe/base'
2
2
 
3
3
  module RedGrape
4
4
  module Pipe
5
+ module In
6
+ def in(*opts)
7
+ InPipe.new self, *opts
8
+ end
9
+ end
10
+
5
11
  class InPipe < Pipe::Base
6
12
  def pipe_name
7
13
  @opts.empty? ? super : "#{super}(#{@opts.first})"
8
14
  end
9
15
 
10
16
  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
17
+ group =
18
+ if self.opts.empty?
19
+ obj.in_edges.map(&:source)
22
20
  else
23
- context.push_history obj do |ctx|
24
- group.pass_through self.next, ctx
25
- end
21
+ label = self.opts.first
22
+ obj.in_edges.find_all{|e| e.label == label}.map(&:source)
26
23
  end
27
- end
24
+ pass_next context, obj, group
28
25
  end
29
26
  end
30
27
  end
@@ -0,0 +1,12 @@
1
+ require 'red_grape/pipe/base'
2
+
3
+ module RedGrape
4
+ module Pipe
5
+ class InVPipe < Pipe::Base
6
+ def pass(obj, context)
7
+ target = obj.target
8
+ pass_next context, obj, target
9
+ end
10
+ end
11
+ end
12
+ end
@@ -3,35 +3,26 @@ require 'red_grape/pipe/base'
3
3
  module RedGrape
4
4
  module Pipe
5
5
  class LoopPipe < Pipe::Base
6
- def pass(obj, context) # TODO: 無理やり・・・
7
- condition = self.opts.first
8
- label = self.opts[1]
6
+ def pass(obj, context)
7
+ condition, label = *self.opts
9
8
 
10
- looped_pipe = self.prev.dup
11
- looped_pipe.prev = self.prev.prev
12
- (label - 1).times do
13
- prev = looped_pipe.prev.dup
14
- prev.next = looped_pipe
15
- looped_pipe = prev
9
+ anchor_pipe = self;
10
+ case label
11
+ when Integer
12
+ label.times {anchor_pipe = anchor_pipe.prev}
13
+ when String, Symbol
14
+ begin
15
+ anchor_pipe = anchor_pipe.prev
16
+ end until anchor_pipe.is_a?(AsPipe) && anchor_pipe.opts.first == label
17
+ else
18
+ raise 'label should be an integer or a string.'
16
19
  end
17
-
18
20
  context.loops += 1
19
- while context.eval :it => obj, &condition
20
- pipe = looped_pipe
21
- while pipe
22
- obj = obj.pass_through pipe, context
23
- pipe = pipe.next
24
- end
25
- context.loops += 1
26
- end
27
- context.loops = 1
28
-
29
- if self.last?
30
- obj
21
+ if context.eval :it => obj, &condition
22
+ obj.pass_through anchor_pipe, context
31
23
  else
32
- context.push_history obj do |ctx|
33
- obj.pass_through self.next, ctx
34
- end
24
+ context.loops = 1
25
+ pass_next context, nil, obj
35
26
  end
36
27
  end
37
28
  end
@@ -0,0 +1,25 @@
1
+ require 'red_grape/pipe/base'
2
+
3
+ module RedGrape
4
+ module Pipe
5
+ module OutE
6
+ def out_e(*opts)
7
+ OutEPipe.new self, *opts
8
+ end
9
+ alias outE out_e
10
+ end
11
+
12
+ class OutEPipe < Pipe::Base
13
+ def pass(obj, context)
14
+ label = self.opts.first
15
+ label = nil if label.is_a?(Array) && label.empty? # TODO
16
+ edges = if label
17
+ obj.out_edges.dup.find_all{|e| e.label == label}
18
+ else
19
+ obj.out_edges.dup
20
+ end
21
+ pass_next context, obj, edges
22
+ end
23
+ end
24
+ end
25
+ end
@@ -14,23 +14,14 @@ module RedGrape
14
14
  end
15
15
 
16
16
  def pass(obj, context)
17
- case obj
18
- when RedGrape::Vertex
19
- group =
20
- if self.opts.empty? or self.opts.first.empty? # TODO $B$J$<$+(Blabel$B$K(B[]$B$,F~$C$F$k(B
21
- VertexGroup.new obj._out_edges.map(&:target)
22
- else
23
- label = self.opts.first
24
- VertexGroup.new obj._out_edges.find_all{|e| e.label == label}.map(&:target)
25
- end
26
- if self.last?
27
- group
17
+ group =
18
+ if self.opts.empty? or self.opts.first.empty? # TODO なぜかlabelに[]が入ってる
19
+ obj.out_edges.map(&:target)
28
20
  else
29
- context.push_history obj do |ctx|
30
- group.pass_through self.next, ctx
31
- end
21
+ label = self.opts.first
22
+ obj.out_edges.find_all{|e| e.label == label}.map(&:target)
32
23
  end
33
- end
24
+ pass_next context, obj, group
34
25
  end
35
26
  end
36
27
  end
@@ -5,20 +5,32 @@ module RedGrape
5
5
  module Pipe
6
6
  class PathsPipe < Pipe::Base
7
7
  def pass(obj, context)
8
- case obj
9
- when 'TODO'
10
- else
11
- context.push_history obj do |ctx|
12
- if self.last?
13
- #ctx.history.dup
14
- PathGroup.new ctx.history
8
+ context.push_history obj do |ctx|
9
+ if self.last?
10
+ history = ctx.history.dup
11
+ if self.opts.empty?
12
+ PathGroup.new history
15
13
  else
16
- # TODO
17
- raise 'not implemented'
14
+ ary = []
15
+ history.each_with_index do |h, index|
16
+ prc = self.opts[index]
17
+ if prc
18
+ context.it = h
19
+ ary << context.eval(&prc)
20
+ else
21
+ ary << h
22
+ end
23
+ end
24
+ PathGroup.new ary
18
25
  end
26
+ else
27
+ # TODO
28
+ raise 'not implemented'
19
29
  end
20
30
  end
21
31
  end
22
32
  end
33
+
34
+ PathPipe = PathsPipe
23
35
  end
24
36
  end
@@ -8,17 +8,8 @@ module RedGrape
8
8
  end
9
9
 
10
10
  def pass(obj, context)
11
- case obj
12
- when RedGrape::Vertex
13
- prop = obj[self.opts.first]
14
- if self.last?
15
- prop
16
- else
17
- context.push_history obj do |ctx|
18
- prop.pass_through self.next, ctx
19
- end
20
- end
21
- end
11
+ prop = obj[self.opts.first]
12
+ pass_next context, obj, prop
22
13
  end
23
14
  end
24
15
  end
@@ -0,0 +1,16 @@
1
+ require 'red_grape/pipe/base'
2
+
3
+ module RedGrape
4
+ module Pipe
5
+ class RetainPipe < Pipe::Base
6
+ def pass(obj, context)
7
+ if context.aggregated_items(self.opts.first).include? obj
8
+ obj
9
+ else
10
+ nil
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -4,17 +4,9 @@ module RedGrape
4
4
  module Pipe
5
5
  class TransformPipe < Pipe::Base
6
6
  def pass(obj, context)
7
- case obj
8
- when 'TODO'
9
- else
10
- transformer = self.opts.first
11
- val = context.eval :it => obj, &transformer
12
- if self.last?
13
- val
14
- else
15
- raise 'not implemented'
16
- end
17
- end
7
+ transformer = self.opts.first
8
+ val = context.eval :it => obj, &transformer
9
+ pass_next context, val
18
10
  end
19
11
  end
20
12
  end
@@ -12,6 +12,8 @@ module RedGrape
12
12
  case type
13
13
  when 'int', 'integer'
14
14
  val.is_a? Integer
15
+ when 'float'
16
+ val.is_a? Numeric
15
17
  else
16
18
  true
17
19
  end
@@ -21,6 +23,8 @@ module RedGrape
21
23
  case type
22
24
  when 'int', 'integer'
23
25
  val =~ /^\d+$/
26
+ when 'float'
27
+ val =~ /^\d+(\.\d+)?$/
24
28
  else
25
29
  true
26
30
  end
@@ -30,6 +34,8 @@ module RedGrape
30
34
  case type
31
35
  when 'int', 'integer'
32
36
  val.to_i
37
+ when 'float'
38
+ val.to_f
33
39
  else
34
40
  val
35
41
  end
@@ -0,0 +1,73 @@
1
+ require 'nokogiri'
2
+
3
+ module RedGrape
4
+ module Serializer
5
+ class GraphMLSerializer
6
+ NAMESPACES = {
7
+ 'xmlns' => 'http://graphml.graphdrawing.org/xmlns',
8
+ 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
9
+ }
10
+
11
+ attr_reader :graph
12
+
13
+ def initialize(graph)
14
+ @graph = graph
15
+ end
16
+
17
+ def load(filename)
18
+ if filename =~ /^<\?xml/
19
+ parse_xml Nokogiri::XML(filename)
20
+ else
21
+ File.open(filename, 'r') do |file|
22
+ parse_xml Nokogiri::XML(file)
23
+ end
24
+ end
25
+ @graph
26
+ end
27
+
28
+ # assumption: any sub-graph does not exist.
29
+ def parse_xml(xml)
30
+ vertices = {}
31
+ edges = {}
32
+ property_descriptions = {}
33
+
34
+ nodes(xml, 'key').each do |key_elm|
35
+ defaults = nodes key_elm, 'default'
36
+ default = defaults.size == 0 ? nil : defaults.first.children.to_s
37
+ prop = PropertyDescription.new key_elm['attr.name'], key_elm['attr.type'], default
38
+ (property_descriptions[key_elm['for']] ||= {})[key_elm['id']] = prop
39
+ end
40
+ @graph.instance_variable_set :@property_descriptions, property_descriptions
41
+
42
+ nodes(xml, 'node').each do |node_elm|
43
+ vertex = Vertex.new @graph, node_elm['id'],
44
+ :property_description => property_descriptions['node']
45
+ data = nodes node_elm, 'data'
46
+ data.each do |data_elm|
47
+ vertex.set_property data_elm['key'], data_elm.children.first.to_s
48
+ end
49
+ vertices[vertex.id] = vertex
50
+ end
51
+ @graph.instance_variable_set :@vertices, vertices
52
+
53
+ nodes(xml, 'edge').each do |edge_elm|
54
+ edge = Edge.new @graph, edge_elm['id'], edge_elm['source'], edge_elm['target'],
55
+ edge_elm['label'], :property_description => property_descriptions['edge']
56
+ data = nodes edge_elm, 'data'
57
+ data.each do |data_elm|
58
+ edge.set_property data_elm['key'], data_elm.children.first.to_s
59
+ end
60
+ edges[edge.id] = edge
61
+ end
62
+ @graph.instance_variable_set :@edges, edges
63
+ end
64
+
65
+ def nodes(xml, elm)
66
+ xml.xpath(".//xmlns:#{elm}", NAMESPACES)
67
+ end
68
+
69
+ def save
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,11 +1,15 @@
1
- require 'red_grape/propertied_object'
1
+ require 'red_grape/element'
2
2
 
3
3
  module RedGrape
4
- class Vertex < PropertiedObject
4
+ class Vertex < Element
5
5
  include RedGrape::Pipe::Out
6
6
  include RedGrape::Pipe::OutE
7
+ include RedGrape::Pipe::In
7
8
  include RedGrape::Pipe::SideEffect
8
9
  include RedGrape::Pipe::As
10
+ include RedGrape::Pipe::Fill
11
+
12
+ attr_reader :id, :out_edges, :in_edges
9
13
 
10
14
  def initialize(graph, id, opts={})
11
15
  super graph, opts
@@ -14,18 +18,6 @@ module RedGrape
14
18
  @in_edges = []
15
19
  end
16
20
 
17
- def _id
18
- @id
19
- end
20
-
21
- def _in_edges
22
- @in_edges
23
- end
24
-
25
- def _out_edges
26
- @out_edges
27
- end
28
-
29
21
  def add_out_edge(edge)
30
22
  @out_edges << edge
31
23
  end
@@ -35,12 +27,7 @@ module RedGrape
35
27
  end
36
28
 
37
29
  def to_s
38
- "v[#{_id}]"
39
- #"v[id(#{_id}):#{@property}]"
40
- end
41
-
42
- def method_missing(name, *args, &block)
43
- self[name.to_s] or raise NoMethodError.new(name.to_s)
30
+ "v[#{@id}]"
44
31
  end
45
32
  end
46
33
  end
data/lib/red_grape.rb CHANGED
@@ -1,4 +1,5 @@
1
- require 'nokogiri'
1
+ require 'ext/object_ext'
2
+ require 'ext/array_ext'
2
3
  require 'red_grape/pipe/in_pipe'
3
4
  require 'red_grape/pipe/out_pipe'
4
5
  require 'red_grape/pipe/property_pipe'
@@ -13,19 +14,27 @@ require 'red_grape/pipe/loop_pipe'
13
14
  require 'red_grape/pipe/has_pipe'
14
15
  require 'red_grape/pipe/out_e_pipe'
15
16
  require 'red_grape/pipe/in_v_pipe'
17
+ require 'red_grape/pipe/aggregate_pipe'
18
+ require 'red_grape/pipe/except_pipe'
19
+ require 'red_grape/pipe/retain_pipe'
20
+ require 'red_grape/pipe/fill_pipe'
21
+ require 'red_grape/pipe/group_count_pipe'
22
+ require 'red_grape/pipe/cap_pipe'
16
23
  require 'red_grape/graph'
17
24
 
18
25
  module RedGrape
19
- VERSION = '0.0.1'
26
+ VERSION = '0.0.2'
20
27
 
21
28
  module_function
29
+ def set_auto_take(val=true)
30
+ Pipe.set_auto_take val
31
+ end
32
+
22
33
  def load_graph(filename)
23
34
  Graph.load filename
24
35
  end
25
- end
26
36
 
27
- class Object
28
- def pass_through(pipe, context)
29
- pipe.pass self, context
37
+ def create_tinker_graph
38
+ Graph.create_tinker_graph
30
39
  end
31
40
  end
@@ -1,12 +1,12 @@
1
1
  require 'test/unit'
2
2
  require 'red_grape'
3
- require 'red_grape/propertied_object'
3
+ require 'red_grape/element'
4
4
  require 'red_grape/property_description'
5
5
 
6
- class PropertiedObjectTest < Test::Unit::TestCase
6
+ class ElementTest < Test::Unit::TestCase
7
7
  def test_new
8
8
  g = RedGrape::Graph.new
9
- v = RedGrape::PropertiedObject.new g, property_description:{
9
+ v = RedGrape::Element.new g, property_description:{
10
10
  name:RedGrape::PropertyDescription.new('name', 'string'),
11
11
  sex:RedGrape::PropertyDescription.new('sex', 'string', 'male'),
12
12
  age:RedGrape::PropertyDescription.new('age', 'integer')
@@ -17,7 +17,7 @@ class PropertiedObjectTest < Test::Unit::TestCase
17
17
  assert_nil desc[:name].default
18
18
  assert_equal 'male', desc[:sex].default
19
19
 
20
- v = RedGrape::PropertiedObject.new g, property_description:{
20
+ v = RedGrape::Element.new g, property_description:{
21
21
  name:['name', 'string'],
22
22
  sex:['sex', 'string', 'male'],
23
23
  age:['age', 'integer']
@@ -28,7 +28,7 @@ class PropertiedObjectTest < Test::Unit::TestCase
28
28
  assert_nil desc[:name].default
29
29
  assert_equal 'male', desc[:sex].default
30
30
 
31
- v = RedGrape::PropertiedObject.new g, property_description:{
31
+ v = RedGrape::Element.new g, property_description:{
32
32
  name:{name:'name', type:'string'},
33
33
  sex:{name:'sex', type:'string', default:'male'},
34
34
  age:{name:'age', type:'integer'}
data/test/test_graph.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'test/unit'
2
- require 'stringio'
3
2
  require 'red_grape'
4
3
 
5
4
  class GraphTest < Test::Unit::TestCase
@@ -10,8 +9,9 @@ class GraphTest < Test::Unit::TestCase
10
9
  graph.add_vertex id:3, val:'c'
11
10
 
12
11
  assert_equal 3, graph.vertex.size
13
- assert_equal 1, graph.vertex(1)._id
14
- assert_equal 2, graph.vertex(1, 2).size
12
+ assert_equal 1, graph.vertex(1).id
13
+ #assert_equal 2, graph.vertex(1, 2).size # TODO
14
+ assert_equal 3, graph.vertex(1, 2, 3).size
15
15
  assert_equal 2, graph.vertex([1, 2]).size
16
16
  assert_equal 3, graph.vertex(:all).size
17
17
  end
@@ -20,15 +20,15 @@ class GraphTest < Test::Unit::TestCase
20
20
  graph = RedGrape::Graph.new
21
21
  v1 = graph.add_vertex 1, name:'yasushi'
22
22
  v2 = graph.add_vertex 2, name:'ando'
23
- e12 = graph.add_edge 1, :fullname, v1, v2
23
+ e12 = graph.add_edge 1, v1, v2, :fullname
24
24
 
25
- assert_equal 1, v1._out_edges.size
26
- assert_equal 0, v1._in_edges.size
27
- assert_equal e12, v1._out_edges.first
25
+ assert_equal 1, v1.out_edges.size
26
+ assert_equal 0, v1.in_edges.size
27
+ assert_equal e12, v1.out_edges.first
28
28
 
29
- assert_equal 0, v2._out_edges.size
30
- assert_equal 1, v2._in_edges.size
31
- assert_equal e12, v2._in_edges.first
29
+ assert_equal 0, v2.out_edges.size
30
+ assert_equal 1, v2.in_edges.size
31
+ assert_equal e12, v2.in_edges.first
32
32
  end
33
33
 
34
34
  def test_load
@@ -67,14 +67,5 @@ class GraphTest < Test::Unit::TestCase
67
67
  assert_equal 'vadas', graph.edge(4).target.name
68
68
  assert_equal 'marko', graph.edge(5).source.name
69
69
  assert_equal 'lop', graph.edge(5).target.name
70
-
71
- graph = RedGrape::Graph.load StringIO.new(data)
72
- assert_equal 'marko', graph.vertex(1).name
73
- assert_equal 'vadas', graph.vertex(2).name
74
- assert_equal 'lop', graph.vertex(3).name
75
- assert_equal 'marko', graph.edge(4).source.name
76
- assert_equal 'vadas', graph.edge(4).target.name
77
- assert_equal 'marko', graph.edge(5).source.name
78
- assert_equal 'lop', graph.edge(5).target.name
79
70
  end
80
71
  end