pacer-jogger 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +30 -18
- data/VERSION +1 -1
- data/lib/jogger.rb +14 -10
- data/pacer-jogger.gemspec +2 -2
- metadata +13 -13
data/README.markdown
CHANGED
@@ -1,56 +1,61 @@
|
|
1
|
-
# Jogger
|
1
|
+
# Jogger - almost like named scopes
|
2
2
|
|
3
3
|
Jogger is a JRuby library that enables lazy people to do very expressive graph traversals with the great [pacer gem](https://github.com/pangloss/pacer). If you don't know what the pacer gem is, you should probably not be here and check pacer out first.
|
4
4
|
|
5
|
-
# What does
|
5
|
+
# What does Jogger do? TL;DR
|
6
|
+
|
7
|
+
Remember the _named scopes_ from back in the days when you were using rails? They were handy, weren't they? Jogger gives you _named traversals_ and is a little bit like named scopes. Jogger groups multiple pacer traversals together and give them a name. Pacer traversals are are like pipes. What are pipes? [Pipes are great!](http://markorodriguez.com/2011/08/03/on-the-nature-of-pipes/)!
|
8
|
+
|
9
|
+
The most important conceptual difference is, that the order in which named traversals are called matter, while it usually doesn't matter in which order you call named scopes.
|
6
10
|
|
7
11
|
Jogger does two things:
|
8
12
|
|
9
13
|
1. Keep the current pacer traversal in an instance variable and allow for method chaining as well as changing the internal state of the traversal
|
10
14
|
2. Allows you to group together parts of a traversal (single pipes or groups of them) and give them a name. Named traversals. Helps to stay DRY.
|
11
15
|
|
12
|
-
The former is really just a syntax thing, whereas the latter can help you a great deal modeling semantics of your business logic as parts of traversals. These sentences confuse me, so I will give you examples.
|
16
|
+
The former is really just a syntax thing, whereas the latter can help you a great deal modeling semantics of your business logic as parts of traversals. These sentences confuse me, so I will give you a TL;DR gif followed by some hands on examples.
|
13
17
|
|
14
|
-
|
18
|
+
![TL;DR](http://dl.dropbox.com/u/1953503/gifs/berneydidnotread.gif)
|
15
19
|
|
16
|
-
|
20
|
+
|
21
|
+
# Feature #1 (not so important): keep the current traversal
|
17
22
|
|
18
23
|
To demonstrate why point 1) in the list above can be useful, look at this traversal. It helps me find out what movies my female friends like the most, so I can impress them in a conversation:
|
19
24
|
|
20
25
|
t = my_pacer_vertex.in(:friends)
|
21
|
-
t = t.filter{
|
26
|
+
t = t.filter{|v| v.properties['gender'] == 'female}
|
22
27
|
t = t.out(:likes)
|
23
28
|
t = t.filter{ |v| v.properties['type'] == 'Movie' }
|
24
|
-
t = t.group_count{ |v| v }
|
25
29
|
t = t.sort_by{ |v, c| -c }
|
30
|
+
t = t.group_count{ |v| v }
|
26
31
|
|
27
32
|
Since I'm a very lazy person, I would prefer to write it a little shorter. Especially, since these multi step traversals are a pattern I found in our code at [moviepilot.com](http://moviepilot.com)) a lot.
|
28
33
|
|
29
|
-
So here's the Jogger way of expressing
|
34
|
+
So here's the Jogger way of expressing this:
|
30
35
|
|
31
36
|
t = Jogger.new(my_pacer_vertex)
|
32
37
|
t.in(:friends)
|
33
38
|
t.filter{ |v| v.properties['gender'] == 'female' }
|
34
39
|
t.out(:likes)
|
35
40
|
t.filter{ |v| v.properties['type'] == 'Movie' }
|
36
|
-
t.group_count{ |v| v }
|
37
41
|
t.sort_by{ |v, c| -c }
|
42
|
+
t.group_count{ |v| v }
|
38
43
|
|
39
44
|
See what I did there? Jogger keeps the current pacer traversal and forwards all method calls to that traversal, and then returns itself. So you could also write (in jogger as well as pacer):
|
40
45
|
|
41
46
|
Jogger.new(my_pacer_node).in(:friends).filter{ … }.out(:likes).group_count{…}
|
42
47
|
|
43
|
-
Just saying, you can chain your methods, but I don't like it
|
48
|
+
Just saying, you can chain your methods, but I don't like it cause I can only focus on 72 characters per line at max. If you want the current traversal, just call `result` on your Jogger instance.
|
44
49
|
|
45
|
-
## 2
|
50
|
+
## Feature #2 (pretty useful): Named Traversals
|
46
51
|
|
47
|
-
So that traversal above, traversing from a node to all its friends, is pretty simple, but it could be simpler. Especially if it does things that you want to reuse in many other places.
|
52
|
+
So that traversal above, traversing from a node to all its friends, is pretty simple, but it could be simpler. Especially if it does things that you want to reuse in many other places. How cool would it be if I just had to write this:
|
48
53
|
|
49
54
|
t = Jogger.new(my_pacer_vertex)
|
50
55
|
t.friends(:female)
|
51
56
|
t.top_list(:movies)
|
52
57
|
|
53
|
-
No problem. Just define
|
58
|
+
No problem. Just define named traversals that aggregate different pipes and give them a name:
|
54
59
|
|
55
60
|
class Jogger
|
56
61
|
module NamedTraversals
|
@@ -60,13 +65,12 @@ No problem. Just define a few named traversals that do exactly this.
|
|
60
65
|
t = current_traversal.in(:friends)
|
61
66
|
t = t.filter{|v| v.properties['gender'] == gender}
|
62
67
|
end
|
63
|
-
|
68
|
+
|
64
69
|
# Group and sort
|
65
70
|
def self.top_list(current_traversal, type)
|
66
71
|
t = current_traversal.out(type)
|
67
72
|
t = t.filter{ |v| v.properties['type'] == 'Movie' }
|
68
73
|
t = t.group_count{ |v| v }
|
69
|
-
t = t.sort_by{ |v, c| -c }
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
@@ -75,16 +79,24 @@ These are silly examples, but if you look at your traversals I guarantee that yo
|
|
75
79
|
|
76
80
|
# Installation
|
77
81
|
|
78
|
-
First, you need to load pacer and whatever graph db connector you need (we use
|
82
|
+
First, you need to load pacer and whatever graph db connector you need (we use neo4j, by the way) and define your named traversals as above. Jogger doesn't include these on purpose. Then, you have to
|
79
83
|
|
80
84
|
gem install pacer-jogger
|
81
85
|
|
82
|
-
and
|
86
|
+
and
|
83
87
|
|
84
88
|
require 'jogger'
|
85
89
|
|
86
|
-
or
|
90
|
+
or for your Gemfile
|
87
91
|
|
88
92
|
gem "pacer-jogger", :require => "jogger"
|
89
93
|
|
90
94
|
That's it!
|
95
|
+
|
96
|
+
# Documentation
|
97
|
+
|
98
|
+
I gave YARD a shot, so to open the documentation in your browser just do this in the jogger directory:
|
99
|
+
|
100
|
+
yard server & sleep 3 && open http://localhost:8808/docs/file/README.markdown
|
101
|
+
|
102
|
+
Or you can (browse the documentation online)[http://rubydoc.info/github/jayniz/jogger/master/frames]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/lib/jogger.rb
CHANGED
@@ -2,21 +2,25 @@
|
|
2
2
|
# Allows to formulate traversals by using predefined
|
3
3
|
# named traversals. Also allows for method chaining.
|
4
4
|
#
|
5
|
-
# All named traversals are defined in {
|
6
|
-
#
|
5
|
+
# All named traversals are defined in {Jogger::NamedTraversals},
|
6
|
+
# so that's where you should define your own.
|
7
7
|
#
|
8
8
|
# Instances have a @current_traversal variable that is
|
9
|
-
# updated with each
|
9
|
+
# updated with each call. Beware: Jogger uses method missing to
|
10
|
+
# delegate unknown methods to the current traversal. So after
|
11
|
+
# you're done chaining things, you can do more stuff with it,
|
12
|
+
# e.g. call count on it:
|
10
13
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
+
# t = Jogger.new(some_node)
|
15
|
+
# t.go.some.where.count
|
16
|
+
#
|
17
|
+
# Everything except for {Jogger#result} is called on the
|
18
|
+
# `@current_traversal`, so what you really want to do to get the
|
19
|
+
# count of your traversal would be
|
14
20
|
#
|
15
21
|
# t = Jogger.new(some_node)
|
16
|
-
# t.
|
22
|
+
# t.go.some.where.result.count
|
17
23
|
#
|
18
|
-
# So everything except for {#traverse} is called on the
|
19
|
-
# @current_traversal
|
20
24
|
class Jogger
|
21
25
|
|
22
26
|
|
@@ -40,7 +44,7 @@ class Jogger
|
|
40
44
|
# This is useful for more traversals after named routes.
|
41
45
|
#
|
42
46
|
# @return [Jogger] Returns itself so you can chain multiple
|
43
|
-
#
|
47
|
+
# calls just like you would do with pacer
|
44
48
|
def method_missing(method, *args, &block)
|
45
49
|
begin
|
46
50
|
traversal_args = [method, args].flatten.compact
|
data/pacer-jogger.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "pacer-jogger"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jannis Hermanns"]
|
12
|
-
s.date = "2012-01-
|
12
|
+
s.date = "2012-01-25"
|
13
13
|
s.description = "Allows to group traversal fragments/pipes to named traversals and call them like they were pacer pipes."
|
14
14
|
s.email = "jannis@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pacer-jogger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
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-01-
|
12
|
+
date: 2012-01-25 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: shoulda
|
16
|
-
requirement: &
|
16
|
+
requirement: &70106294753680 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70106294753680
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &70106294753160 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.0.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70106294753160
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: jeweler
|
38
|
-
requirement: &
|
38
|
+
requirement: &70106294752640 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.7.0
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70106294752640
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70106294752040 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70106294752040
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: yard
|
60
|
-
requirement: &
|
60
|
+
requirement: &70106294751440 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70106294751440
|
69
69
|
description: Allows to group traversal fragments/pipes to named traversals and call
|
70
70
|
them like they were pacer pipes.
|
71
71
|
email: jannis@gmail.com
|
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
101
|
version: '0'
|
102
102
|
segments:
|
103
103
|
- 0
|
104
|
-
hash:
|
104
|
+
hash: 3011242392760856399
|
105
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
106
|
none: false
|
107
107
|
requirements:
|