neo4jr-social 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -17,5 +17,7 @@ tmtags
17
17
  coverage
18
18
  rdoc
19
19
  pkg
20
+ tmp
20
21
 
21
22
  ## PROJECT::SPECIFIC
23
+ .idea
data/README.rdoc CHANGED
@@ -2,90 +2,31 @@
2
2
 
3
3
  Neo4jr-Social is a self contained HTTP REST + JSON interface to the graph database Neo4j. Neo4jr-Social supports simple dynamic node creation, building relationships between nodes and also includes a few common social networking queries out of the box (i.e. linkedin degrees of seperation and facebook friend suggestion) with more to come. Think of Neo4jr-Social is to Neo4j like Solr is to Lucene.
4
4
 
5
- Neo4jr-Social was built in JRuby but is language agnostic and is designed to run under Jetty or Tomcat.
5
+ Neo4jr-Social was built in JRuby but is language agnostic and is designed to run as a self-contained service or can be deployed under Jetty or Tomcat.
6
6
 
7
7
  = Getting Started
8
8
 
9
- === Prerequisites
9
+ == Prerequisites
10
+
10
11
  * Java
11
12
  * JRuby: http://jruby.org
12
13
 
13
- === Installing
14
- Install Ruby Gem: json_pure
15
- jgem install json_pure
16
- Install Ruby Gem: sinatra
17
- jgem install sinatra
18
- Install Ruby Gem: neo4jr-simple
19
- jgem install neo4jr-simple
20
- Install Ruby Gem: neo4jr-social
21
- jgem install neo4jr-simple
22
-
23
- === Starting Neo4jr-Social
14
+ == Running Neo4jr-Social
24
15
 
25
- After installing the above gems, an executable 'start-neo4jr-social' should be in your path. This will start the service and the database and listen for HTTP requests on localhost at port 8988:
16
+ After installing the above gems, an executable 'start-neo4jr-social' should be in your $PATH. This will start the service and the database and listen for HTTP requests on localhost at port 8988 by default:
26
17
 
27
18
  start-neo4jr-social -p8988
28
19
 
29
20
  You can also start the service and specify the directory of where the neo4j database is stored or where to create a new database. If you omit this setting a database will be created in your tmp directory and destroyed when you shutdown the server.
30
21
 
31
22
  start-neo4jr-social -p8988 -dsome_relative_or_absolute_directory
32
-
23
+
33
24
  Run start-neo4jr-social --help to see all options
34
25
 
35
- === API Overview
36
- All results returned will be in JSON
37
-
38
- ==== GET /info
39
- Returns details about the Neo4j database like the location of the database and the number of nodes.
40
-
41
- ==== GET /nodes
42
- Returns all nodes in the database. Use this method with caution, this could crash your server if you have a database with more then a few thousand nodes.
43
-
44
- ==== POST /nodes
45
- Creates a new node in the neo4j database. Any parameters based in the body of the POST will be treated as properties for the node and will be stored in the database.
46
-
47
- ==== GET /nodes/:node_id
48
- Returns the properties for the specified node, where :node_id is the numeric id for the node
49
-
50
- ==== PUT /nodes/:node_id
51
- Updates the properties of the specified node, where :node_id is the numeric id for the node. Any parameters pased in the body of the PUT will be treated as properties for the node. If you add a new parameters (i.e. age=4) which previously were not on the node, neo4jr-social will still add that property to the node.
52
-
53
- ==== DELETE /nodes/:node_id
54
- Deletes the specified node, where :node_id is the numeric id for the node.
55
-
56
- ==== POST /nodes/:node_id/relationships
57
- Creates a relations for the specified node, where :node_id is the numeric id for the node. This is how you designate how two nodes are related to each other.
58
- * Required: to - this is the node id of the node you want to make a relationship to. This is a one-way relationship. If you want both nodes to be related to each other you will need to make individual POSTs for each direction of the relationship.
59
- * Required: type - this is the type of the relationship, i.e. 'friends'. This can be any string that is sensible in your domain.
60
- * Optional: Any other parameters you supply in the body of the POST will be added as properties to the relationship. For example if you were making 'friend' relationships and wanted to add a date since the friendship started you could pass a 'since' parameter in the POST.
61
-
62
- ==== GET /nodes/:node_id/relationships
63
- Returns relationships to other nodes for the specified node, where :node_id is the numeric id for the node.
64
- * Optional: type - Specify a type if only certain relationships are of interest
65
-
66
- ==== GET /nodes/:node_id/paths
67
- This returns all the ways two nodes are connected to each other and is similar to LinkedIn's degrees of separation.
68
- * Required: to - the id of the node that your trying to find a path to from the starting node, :node_id
69
- * Required: type - the type of relationships between nodes to follow
70
- * Optional: depth - maximum degrees of separation to find, the default is 2 degrees. Note: There may be performance impacts if this number is to high.
71
- * Optional: direction - What direction of relationships to follow, the default is 'both'
72
-
73
- ==== GET /nodes/:node_id/shortest_path
74
- This returns the shortest path of two nodes that are connected to each other
75
- * Required: to - the id of the node that your trying to find a path to from the starting node, :node_id
76
- * Required: type - the type of relationships between nodes to follow
77
-
78
- ==== GET /nodes/:node_id/recommendations
79
- This returns node suggestions for the given :node_id. This is similar to facebook friend suggestions where your friend's friends that your not friends with are suggested to you.
80
- * Required: type - the type of relationships between nodes to follow
81
- * Optional: level - the degree of separation that you want recommendations for, the default is 1 degree away which is similar to facebook's behavior
82
-
83
-
84
- == Troubleshooting
85
-
86
- /usr/bin/env: jruby: No such file or directory
87
-
88
- You need to either install jruby or if you used a utility like rvm then your jruby executable may actually be called jruby-1.4, if this is the case create an alias somewhere in your PATH
26
+ === API
27
+
28
+ The service is documented at http://wiki.github.com/mdeiters/neo4jr-social/
29
+
89
30
  == Contributors
90
31
 
91
32
  ====Matthew Deiters
data/Rakefile CHANGED
@@ -15,11 +15,9 @@ begin
15
15
  gem.authors = ["Matthew Deiters"]
16
16
  gem.add_development_dependency "rspec", ">= 1.2.9"
17
17
  gem.add_development_dependency "rest-client"
18
- gem.add_dependency 'neo4jr-simple', ">= 0.1.6" unless ENV['dev_on_gem']
18
+ gem.add_dependency 'neo4jr-simple', ">= 0.1.6" unless ENV['neo4jr_simple']
19
19
  gem.add_dependency 'sinatra'
20
20
  gem.add_dependency 'json_pure'
21
-
22
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
23
21
  end
24
22
  Jeweler::GemcutterTasks.new
25
23
  rescue LoadError
data/TODO CHANGED
@@ -1,9 +1,9 @@
1
- * Figure out a better way to shebang for start-neo4jr-social
2
1
  * Validate requests, check parameters, etc
3
- * Figure out how we should handle the Neo4j node's classname
2
+ * Retrieve Node by identifier other then node id
3
+ * Figure out how to handle the Neo4j nodes classname
4
+ * More querying potential: Enable solr type parameters with lt gt eq etc or enable gremlin
5
+ Examples
4
6
  * Query Type: Amazon Recommendations
5
7
  * Query Type: Most Popular
6
8
  * Query Type: Primitive dynamic querying on all nodes
7
- * Enable solr type parameters with lt gt eq etc
8
- * Explore vendor-ize all ruby libs into WEB-INF
9
9
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
data/config/warble.rb ADDED
@@ -0,0 +1,18 @@
1
+ # Warbler web application assembly configuration file
2
+ Warbler::Config.new do |config|
3
+ config.dirs = %w(lib)
4
+ config.includes = FileList["config.ru"]
5
+
6
+ config.gems['sinatra'] = '0.9.4'
7
+ config.gems['json_pure'] = '1.2.0'
8
+ config.gems['neo4jr-simple'] = '0.1.7'
9
+
10
+ config.gem_dependencies = true
11
+ config.webxml.booter = :rack
12
+
13
+ # Control the pool of runtimes. Leaving unspecified means
14
+ # the pool will grow as needed to service requests. It is recommended
15
+ # that you fix these values when running a production server!
16
+ # config.webxml.jruby.min.runtimes = 2
17
+ # config.webxml.jruby.max.runtimes = 4
18
+ end
data/examples/facebook.rb CHANGED
@@ -30,4 +30,6 @@ make_mutual_friends(phill, mary)
30
30
  make_mutual_friends(phill, luke)
31
31
 
32
32
  puts "Johnathan should become friends with #{suggestions_for(johnathan).map{|n| n['name']}.join(', ')}"
33
- #=> Johnathan should become friends with Mary, Phill
33
+
34
+ # RESULT
35
+ # Johnathan should become friends with Mary, Phill
data/examples/linkedin.rb CHANGED
@@ -34,5 +34,6 @@ degrees_of_seperation(johnathan, mary).each do |path|
34
34
  puts path.map{|node| node['name'] || node['type']}.join(' => ')
35
35
  end
36
36
 
37
+ # RESULT
37
38
  # Johnathan => friends => Mark => friends => Phill => friends => Mary
38
39
  # Johnathan => friends => Mark => friends => Mary
@@ -0,0 +1,50 @@
1
+ module Neo4jr
2
+ module FormatHandler
3
+ def self.registered(app)
4
+ app.send :mime, :json, 'application/json'
5
+ app.set :assume_xhr_is_js, true
6
+ app.helpers self
7
+ app.before do
8
+ if request.env['HTTP_ACCEPT'] && request.env['HTTP_ACCEPT'].include?('text/html')
9
+ format :html
10
+ else
11
+ format :json
12
+ end
13
+ charset 'utf-8'
14
+ end
15
+ end
16
+
17
+ def render_for_format(data)
18
+ case format
19
+ when :json : return JsonPrinter.render(data)
20
+ when :html : return JsonPrinter.render_html(data)
21
+ else
22
+ fail("#{format} is not a supported MIME type")
23
+ end
24
+ end
25
+
26
+ def format(val=nil)
27
+ unless val.nil?
28
+ mime_type = media_type(val)
29
+ fail "Unknown media type #{val}\nTry registering the extension with a mime type" if mime_type.nil?
30
+
31
+ @format = val.to_sym
32
+ response['Content-Type'].sub!(/^[^;]+/, mime_type)
33
+ end
34
+
35
+ @format
36
+ end
37
+
38
+ def charset(val=nil)
39
+ fail "Content-Type must be set in order to specify a charset" if response['Content-Type'].nil?
40
+
41
+ if response['Content-Type'] =~ /charset=[^;]+/
42
+ response['Content-Type'].sub!(/charset=[^;]+/, (val == '' && '') || "charset=#{val}")
43
+ else
44
+ response['Content-Type'] += ";charset=#{val}"
45
+ end unless val.nil?
46
+
47
+ response['Content-Type'][/charset=([^;]+)/, 1]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,154 @@
1
+ # Please see http://github.com/techcrunch/json_printer
2
+ #
3
+ class JsonPrinter
4
+ attr_reader :buf, :indent
5
+
6
+ # ==== Arguments
7
+ # obj<Object>::
8
+ # The object to be rendered into JSON. This object and all of its
9
+ # associated objects must be either nil, true, false, a String, a Symbol,
10
+ # a Numeric, an Array, or a Hash.
11
+ #
12
+ # ==== Returns
13
+ # <String>::
14
+ # The pretty-printed JSON ecoding of the given <i>obj</i>. This string
15
+ # can be parsed by any compliant JSON parser without modification.
16
+ #
17
+ # ==== Examples
18
+ # See <tt>JsonPrinter</tt> docs.
19
+ #
20
+ def self.render(obj)
21
+ new(obj).buf
22
+ end
23
+
24
+ def self.render_html(obj)
25
+ render(obj).gsub(' ', '&nbsp;').gsub("\n", "<br>")
26
+ end
27
+
28
+ private
29
+
30
+ # Execute the JSON rendering of <i>obj</i>, storing the result in the
31
+ # <tt>buf</tt>.
32
+ #
33
+ def initialize(obj)
34
+ @buf = ""
35
+ @indent = ""
36
+ render(obj)
37
+ end
38
+
39
+ # Increase the indentation level.
40
+ #
41
+ def indent_out
42
+ @indent << " "
43
+ end
44
+
45
+ # Decrease the indendation level.
46
+ #
47
+ def indent_in
48
+ @indent.slice!(-1, 1)
49
+ end
50
+
51
+ # Append the given <i>str</i> to the <tt>buf</tt>.
52
+ #
53
+ def print(str)
54
+ @buf << str
55
+ end
56
+
57
+
58
+ # Recursive rendering method. Primitive values, like nil, true, false,
59
+ # numbers, symbols, and strings are converted to JSON and appended to the
60
+ # buffer. Enumerables are treated specially to generate pretty whitespace.
61
+ #
62
+ def render(obj)
63
+ # We can't use a case statement here becuase "when Hash" doesn't work for
64
+ # ActiveSupport::OrderedHash - respond_to?(:values) is a more reliable
65
+ # indicator of hash-like behavior.
66
+ if NilClass === obj
67
+ print("null")
68
+
69
+ elsif TrueClass === obj
70
+ print("true")
71
+
72
+ elsif FalseClass === obj
73
+ print("false")
74
+
75
+ elsif String === obj
76
+ print(escape_json_string(obj))
77
+
78
+ elsif Symbol === obj
79
+ print("\"#{obj}\"")
80
+
81
+ elsif Numeric === obj
82
+ print(obj.to_s)
83
+
84
+ elsif Time === obj
85
+ print(obj.to_s)
86
+
87
+ elsif obj.respond_to?(:keys)
88
+ print("{")
89
+ indent_out
90
+ last_key = obj.keys.last
91
+ obj.each do |(key, val)|
92
+ render(key)
93
+ case val
94
+ when Hash, Array
95
+ indent_out
96
+ print(":\n#{indent}")
97
+ render(val)
98
+ indent_in
99
+ else
100
+ print(": ")
101
+ render(val)
102
+ end
103
+ print(",\n#{indent}") unless key == last_key
104
+ end
105
+ indent_in
106
+ print("}")
107
+
108
+ elsif Array === obj
109
+ print("[")
110
+ indent_out
111
+ last_index = obj.size - 1
112
+ obj.each_with_index do |elem, index|
113
+ render(elem)
114
+ print(",\n#{indent}") unless index == last_index
115
+ end
116
+ indent_in
117
+ print("]")
118
+
119
+ else
120
+ raise "unrenderable object: #{obj.inspect}"
121
+ end
122
+ end
123
+
124
+ # Special JSON character escape cases.
125
+ ESCAPED_CHARS = {
126
+ "\010" => '\b',
127
+ "\f" => '\f',
128
+ "\n" => '\n',
129
+ "\r" => '\r',
130
+ "\t" => '\t',
131
+ '"' => '\"',
132
+ '\\' => '\\\\',
133
+ '>' => '\u003E',
134
+ '<' => '\u003C',
135
+ '&' => '\u0026'}
136
+
137
+ # String#to_json extracted from ActiveSupport, using interpolation for speed.
138
+ #
139
+ def escape_json_string(str)
140
+ begin
141
+ "\"#{
142
+ str.gsub(/[\010\f\n\r\t"\\><&]/) { |s| ESCAPED_CHARS[s] }.
143
+ gsub(/([\xC0-\xDF][\x80-\xBF]|
144
+ [\xE0-\xEF][\x80-\xBF]{2}|
145
+ [\xF0-\xF7][\x80-\xBF]{3})+/nx) do |s|
146
+ s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&')
147
+ end
148
+ }\""
149
+ rescue Encoding::CompatibilityError
150
+ rawbytes = str.dup.force_encoding 'ASCII-8BIT'
151
+ escape_json_string(rawbytes)
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,32 @@
1
+ module Neo4jr
2
+ module ParamHelper
3
+
4
+ def param_node_id
5
+ params.delete('node_id')
6
+ end
7
+
8
+ def param_relationship_type
9
+ @param_relationship_type ||= params.delete('type')
10
+ end
11
+
12
+ def param_to_node_id
13
+ params.delete('to')
14
+ end
15
+
16
+ def param_depth
17
+ (params.delete('depth') || 2).to_i
18
+ end
19
+
20
+ def param_level
21
+ @param_level ||= (params.delete('level') || 1).to_i
22
+ end
23
+
24
+ def param_direction
25
+ Neo4jr::Direction.from_string(params.delete('direction') || 'both')
26
+ end
27
+
28
+ def relationship_types
29
+ (param_relationship_type.nil? ? [] : [param_relationship_type].flatten.map {|name| DynamicRelationshipType.with_name(name)}).to_java(DynamicRelationshipType)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ module Neo4jr
2
+ module SelfDocumentor
3
+ def describe(info)
4
+ SelfDocumentor.capture info
5
+ end
6
+
7
+ def required_param(*args)
8
+ SelfDocumentor.required_param(*args)
9
+ end
10
+
11
+ def optional_param(*args)
12
+ SelfDocumentor.optional_param(*args)
13
+ end
14
+
15
+ def self.required_param(*args)
16
+ (@capture_required_param ||= []) << {args.first => args.last}
17
+ end
18
+
19
+ def self.optional_param(*args)
20
+ args.unshift(:note) if args.size == 1
21
+ (@capture_optional_param ||= []) << {args.first => args.last}
22
+ end
23
+
24
+ def self.capture(text)
25
+ @capture = text
26
+ end
27
+
28
+ def self.route_added(verb, path, proc)
29
+ if [:get, :post, :put, :delete].include?(verb.downcase.to_sym)
30
+ document = {:path => path, :description => (@capture || '').to_s}
31
+ document[:required] = @capture_required_param if @capture_required_param
32
+ document[:optional] = @capture_optional_param if @capture_optional_param
33
+ (@@document ||= []) << document
34
+ @capture_optional_param = nil
35
+ @capture_required_param = nil
36
+ end
37
+ end
38
+
39
+ def self.output
40
+ @@document
41
+ end
42
+ end
43
+ end
@@ -1,114 +1,144 @@
1
1
  module Neo4jr
2
2
  class Service < Sinatra::Base
3
-
3
+ helpers ParamHelper
4
+ register SelfDocumentor, FormatHandler
5
+
6
+ describe "Lists all possible request types with descriptions"
7
+ get '/' do
8
+ render_for_format(SelfDocumentor.output)
9
+ end
10
+
11
+ describe "Returns details about the Neo4j database like the location of the database and the number of nodes."
4
12
  get '/info' do
5
13
  Neo4jr::DB.stats.to_json
6
14
  end
7
-
15
+
16
+ describe "Returns all nodes in the database. Use this method with caution, this could crash your server if you have a database with more then a few thousand nodes."
8
17
  get '/nodes' do
9
18
  nodes = Neo4jr::DB.execute do |neo|
10
- nodes = neo.all_nodes.map{|m| m.to_hash }
19
+ nodes = neo.all_nodes.map{|m| m.to_hash }
11
20
  end
12
21
  nodes.to_json
13
22
  end
14
-
23
+
24
+ describe "Creates a new node in the neo4j database. Any parameters based in the body of the POST will be treated as properties for the node and will be stored in the database."
15
25
  post '/nodes' do
16
26
  node = Neo4jr::DB.execute do |neo|
17
27
  node = neo.create_node(params)
18
28
  end
19
29
  node.to_hash.to_json
20
30
  end
21
-
31
+
32
+ describe "Returns the properties for the specified node, where :node_id is the numeric id for the node."
22
33
  get '/nodes/:node_id' do
23
- Neo4jr::DB.getNodeById(params.delete('node_id')).to_json
34
+ node = Neo4jr::DB.execute do |neo|
35
+ neo.getNodeById(param_node_id).to_hash.to_json
36
+ end
24
37
  end
25
-
38
+
39
+ describe "Updates the properties of the specified node, where :node_id is the numeric id for the node. Any parameters pased in the body of the PUT will be treated as properties for the node. If you add a new parameters (i.e. age=4) which previously were not on the node, neo4jr-social will still add that property to the node."
26
40
  put '/nodes/:node_id' do
27
41
  node = Neo4jr::DB.execute do |neo|
28
- node = neo.getNodeById(params.delete('node_id'))
42
+ node = neo.getNodeById(param_node_id)
29
43
  node.update_properties(params)
30
44
  end
31
45
  node.to_hash.to_json
32
46
  end
33
-
47
+
48
+ describe "Deletes the specified node, where :node_id is the numeric id for the node."
34
49
  delete '/nodes/:node_id' do
35
50
  Neo4jr::DB.execute do |neo|
36
- node = neo.getNodeById(params['node_id'])
51
+ node = neo.getNodeById(param_node_id)
52
+ node.get_relationships.each { |r| r.delete }
37
53
  node.delete
38
54
  end
39
55
  end
40
-
56
+
57
+ describe "Creates a relations for the specified node, where :node_id is the numeric id for the node. This is how you designate how two nodes are related to each other."
58
+ required_param :to, 'This is the node id of the node you want to make a relationship to. This is a one-way relationship. If you want both nodes to be.'
59
+ required_param :type, "this is the type of the relationship, i.e. 'friends'. This can be any string that is sensible in your domain."
60
+ optional_param "Any other parameters you supply in the body of the POST will be added as properties to the relationship. For example if you were making 'friend' relationships and wanted to add a date since the friendship started you could pass a 'since' parameter in the POST."
41
61
  get '/nodes/:node_id/relationships' do
42
62
  relationships = Neo4jr::DB.execute do |neo|
43
- node = neo.getNodeById(params.delete('node_id'))
44
- if relationship_type = params.delete('type')
45
- relationship_type = RelationshipType.instance(relationship_type)
46
- node.getRelationships(relationship_type.to_a).hashify_objects
63
+ node = neo.getNodeById(param_node_id)
64
+ if param_relationship_type
65
+ relationship_type = RelationshipType.instance(param_relationship_type)
66
+ node.getRelationships(param_relationship_type.to_a).hashify_objects
47
67
  else
48
68
  node.getRelationships.hashify_objects
49
69
  end
50
70
  end
51
71
  relationships.to_json
52
72
  end
53
-
73
+
74
+ describe "Returns relationships to other nodes for the specified node, where :node_id is the numeric id for the node."
75
+ optional_param :type, "Specify a type if only certain relationships are of interest"
54
76
  post '/nodes/:node_id/relationships' do
55
77
  relationships = Neo4jr::DB.execute do |neo|
56
- node = neo.getNodeById(params.delete('node_id'))
57
- to_node = neo.getNodeById(params.delete('to'))
58
- relationship_type = RelationshipType.instance(params.delete('type'))
59
- relationship = node.create_relationship_to to_node, relationship_type
78
+ node = neo.getNodeById(param_node_id)
79
+ to_node = neo.getNodeById(param_to_node_id)
80
+ relationship_type = RelationshipType.instance(param_relationship_type)
81
+ relationship = node.create_relationship_to to_node, relationship_type
60
82
  relationship.update_properties(params)
61
83
  node.getRelationships(relationship_type.to_a).hashify_objects
62
84
  end
63
85
  relationships.to_json
64
86
  end
65
87
 
88
+ describe "This returns all the ways two nodes are connected to each other and is similar to LinkedIn's degrees of separation. Warning: This is only good for sparse graphs, shortest_paths is better at handling larger connected graphs."
89
+ required_param :to, "the id of the node that your trying to find a path to from the starting node, :node_id"
90
+ required_param :type, "the type of relationships between nodes to follow"
91
+ optional_param :depth, "the maximum degrees of separation to find, the default is 2 degrees. Note: There may be performance impacts if this number is to high."
92
+ optional_param :direction, "hat direction of relationships to follow, the default is 'both'"
66
93
  get '/nodes/:node_id/paths' do
67
94
  paths = Neo4jr::DB.execute do |neo|
68
- start_node = neo.getNodeById(params.delete('node_id'))
69
- end_node = neo.getNodeById(params.delete('to'))
70
- relationship = Neo4jr::RelationshipType.instance(params.delete('type'))
71
- depth = params.delete('depth') || 2
72
- direction = Neo4jr::Direction.from_string(params.delete('direction') || 'both')
73
- shortest_path = AllSimplePaths.new(start_node, end_node, depth.to_i, direction, relationship.to_a)
74
- paths = shortest_path.getPaths
75
- paths.map{|p| p.map{|n| n.to_hash }}
95
+ start_node = neo.getNodeById(param_node_id)
96
+ end_node = neo.getNodeById(param_to_node_id)
97
+ shortest_path = AllSimplePaths.new(start_node, end_node, param_depth, param_direction, relationship_types)
98
+ to_hash shortest_path.getPaths
76
99
  end
77
100
  paths.to_json
78
101
  end
79
-
102
+
103
+ describe "This returns the first of the shortest path of two nodes that are connected to each other"
104
+ required_param :to, "the id of the node that your trying to find a path to from the starting node, :node_id"
105
+ required_param :type, "the type of relationships between nodes to follow"
80
106
  get '/nodes/:node_id/shortest_path' do
81
107
  path = Neo4jr::DB.execute do |neo|
82
- start_node = neo.getNodeById(params.delete('node_id'))
83
- end_node = neo.getNodeById(params.delete('to'))
84
- relationship = Neo4jr::RelationshipType.instance(params.delete('type'))
85
- dijkstra = Neo4jr::Dijkstra.new(
108
+ dijkstra = Dijkstra.new(
86
109
  0.0,
87
- start_node,
88
- end_node,
110
+ neo.getNodeById(param_node_id),
111
+ neo.getNodeById(param_to_node_id),
89
112
  Neo4jr::SimpleEvaluator.new,
90
113
  DoubleAdder.new,
91
114
  DoubleComparator.new,
92
- Direction::BOTH,
93
- relationship.to_a)
94
- dijkstra.getPath.map{|n| n.to_hash }
115
+ direction,
116
+ relationship_types)
117
+ (p=dijkstra.getPath) and p.map{|n| n.to_hash }
95
118
  end
96
119
  path.to_json
97
120
  end
98
-
121
+
122
+ describe "This returns node suggestions for the given :node_id. This is similar to facebook friend suggestions where your friend's friends that your not friends with are suggested to you."
123
+ required_param :type, "the type of relationships between nodes to follow"
124
+ optional_param :leve, "the degree of separation that you want recommendations for, the default is 1 degree away which is similar to facebook's behavior"
99
125
  get '/nodes/:node_id/recommendations' do
100
126
  suggestions = Neo4jr::DB.execute do |neo|
101
- relationship = Neo4jr::RelationshipType.incoming(params.delete('type'))
102
- start_node = neo.getNodeById(params.delete('node_id'))
103
- level = (params.delete('level') || 1).to_i
104
- order = Order::BREADTH_FIRST
105
- return_when = Return.when do |current_position|
106
- current_position.depth > level
127
+ relationship = Neo4jr::RelationshipType.incoming(param_relationship_type)
128
+ start_node = neo.getNodeById(param_node_id)
129
+ order = Order::BREADTH_FIRST
130
+ return_when = Return.when do |current_position|
131
+ current_position.depth > param_level
107
132
  end
108
- traverser = start_node.traverse(order, Stop.at(level + 1), return_when, relationship)
133
+ traverser = start_node.traverse(order, Stop.at(param_level + 1), return_when, relationship)
109
134
  traverser.map{|node| node.to_hash }
110
135
  end
111
136
  suggestions.to_json
112
137
  end
138
+
139
+ private
140
+ def to_hash paths
141
+ paths and paths.map{|p| p.map{|n| n.to_hash }}
142
+ end
113
143
  end
114
144
  end
data/lib/neo4jr-social.rb CHANGED
@@ -1,15 +1,48 @@
1
1
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
2
2
 
3
+ def find_and_require_neo4jr_simple
4
+ neo4jr_simple_root = java.lang.System.getProperty('neo4jr.simple') || ENV['neo4jr_simple']
5
+ if neo4jr_simple_root
6
+ $LOAD_PATH.unshift(File.join(neo4jr_simple_root, 'lib'))
7
+ else
8
+ gem 'neo4jr-simple'
9
+ end
10
+ require 'neo4jr-simple'
11
+ end
12
+
13
+ def find_and_require_user_defined_code
14
+ extensions_path = java.lang.System.getProperty('neo4jr.extensions') || ENV['neo4jr_extensions'] || "~/.neo4jr-social"
15
+ extensions_path = File.expand_path(extensions_path)
16
+ if File.exists?(extensions_path)
17
+ Dir.open extensions_path do |dir|
18
+ dir.entries.each do |file|
19
+ if file.split('.').size > 1 && file.split('.').last == 'rb'
20
+ extension = File.join(File.expand_path(extensions_path), file)
21
+ require(extension) && puts("Loaded Extension: #{extension}")
22
+ end
23
+ end
24
+ end
25
+ else
26
+ puts "No Extensions Found: #{extensions_path}"
27
+ end
28
+ end
29
+
3
30
  include Java
4
31
 
5
32
  require 'rubygems'
33
+
6
34
  gem 'sinatra'
7
- gem 'json_pure'
8
- gem 'neo4jr-simple' unless ENV['dev_on_gem']
35
+ gem 'json_pure'
9
36
 
10
37
  require 'sinatra'
11
38
  require 'json'
12
- require 'neo4jr-simple'
13
- require 'neo4jr-social/simple_cost_evaluator'
39
+
40
+ find_and_require_neo4jr_simple
41
+
42
+ require 'neo4jr-social/self_documentor'
43
+ require 'neo4jr-social/param_helper'
44
+ require 'neo4jr-social/format_handler'
45
+ require 'neo4jr-social/json_printer'
14
46
  require 'neo4jr-social/service'
15
47
 
48
+ find_and_require_user_defined_code
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{neo4jr-social}
8
- s.version = "0.1.1"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Matthew Deiters"]
12
- s.date = %q{2009-12-26}
12
+ s.date = %q{2010-01-19}
13
13
  s.default_executable = %q{start-neo4jr-social}
14
14
  s.description = %q{A self-containted lightweight REST interface to Neo4j using JRuby }
15
15
  s.email = %q{matthew_deiters@mckinsey.com}
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  "VERSION",
30
30
  "bin/start-neo4jr-social",
31
31
  "config.ru",
32
+ "config/warble.rb",
32
33
  "examples/facebook.rb",
33
34
  "examples/linkedin.rb",
34
35
  "jetty-runtime/etc/jetty.xml",
@@ -43,20 +44,17 @@ Gem::Specification.new do |s|
43
44
  "jetty-runtime/start.jar",
44
45
  "jetty-runtime/webapps/neo4jr-social.war",
45
46
  "lib/neo4jr-social.rb",
47
+ "lib/neo4jr-social/format_handler.rb",
48
+ "lib/neo4jr-social/json_printer.rb",
49
+ "lib/neo4jr-social/param_helper.rb",
50
+ "lib/neo4jr-social/self_documentor.rb",
46
51
  "lib/neo4jr-social/service.rb",
47
- "lib/neo4jr-social/simple_cost_evaluator.rb",
48
- "lib/neo4jr-social/version.rb",
49
52
  "neo4jr-social.gemspec",
53
+ "spec/format_handler_spec.rb",
54
+ "spec/json_printer_spec.rb",
50
55
  "spec/service_spec.rb",
51
56
  "spec/spec.opts",
52
- "spec/spec_helper.rb",
53
- "tmp/war/WEB-INF/lib/jruby-core-1.4.0.jar",
54
- "tmp/war/WEB-INF/lib/jruby-rack-0.9.5.jar",
55
- "tmp/war/WEB-INF/lib/jruby-stdlib-1.4.0.jar",
56
- "tmp/war/WEB-INF/lib/neo4jr-social.rb",
57
- "tmp/war/WEB-INF/lib/neo4jr-social/service.rb",
58
- "tmp/war/WEB-INF/lib/neo4jr-social/version.rb",
59
- "tmp/war/WEB-INF/web.xml"
57
+ "spec/spec_helper.rb"
60
58
  ]
61
59
  s.homepage = %q{http://github.com/mdeiters/neo4jr-social}
62
60
  s.rdoc_options = ["--charset=UTF-8"]
@@ -64,7 +62,9 @@ Gem::Specification.new do |s|
64
62
  s.rubygems_version = %q{1.3.5}
65
63
  s.summary = %q{A self-containted and lightweight REST interface to Neo4j using JRuby.}
66
64
  s.test_files = [
67
- "spec/service_spec.rb",
65
+ "spec/format_handler_spec.rb",
66
+ "spec/json_printer_spec.rb",
67
+ "spec/service_spec.rb",
68
68
  "spec/spec_helper.rb",
69
69
  "examples/facebook.rb",
70
70
  "examples/linkedin.rb"
@@ -77,20 +77,17 @@ Gem::Specification.new do |s|
77
77
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
78
78
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
79
79
  s.add_development_dependency(%q<rest-client>, [">= 0"])
80
- s.add_runtime_dependency(%q<neo4jr-simple>, [">= 0.1.6"])
81
80
  s.add_runtime_dependency(%q<sinatra>, [">= 0"])
82
81
  s.add_runtime_dependency(%q<json_pure>, [">= 0"])
83
82
  else
84
83
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
85
84
  s.add_dependency(%q<rest-client>, [">= 0"])
86
- s.add_dependency(%q<neo4jr-simple>, [">= 0.1.6"])
87
85
  s.add_dependency(%q<sinatra>, [">= 0"])
88
86
  s.add_dependency(%q<json_pure>, [">= 0"])
89
87
  end
90
88
  else
91
89
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
92
90
  s.add_dependency(%q<rest-client>, [">= 0"])
93
- s.add_dependency(%q<neo4jr-simple>, [">= 0.1.6"])
94
91
  s.add_dependency(%q<sinatra>, [">= 0"])
95
92
  s.add_dependency(%q<json_pure>, [">= 0"])
96
93
  end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Neo4jr::FormatHandler do
4
+
5
+ it 'returns pure json by default' do
6
+ get '/'
7
+ last_response.body.should_not include(html_space = '&nbsp;')
8
+ last_response.headers['Content-Type'].should include('application/json')
9
+ end
10
+
11
+ it 'returns htmlized json if a browser request' do
12
+ get '/', {}, {'HTTP_ACCEPT' => 'text/html'}
13
+ last_response.body.should include(html_space = '&nbsp;')
14
+ last_response.headers['Content-Type'].should include('text/html')
15
+ end
16
+
17
+ it 'always returns utf compliant text' do
18
+ get '/'
19
+ last_response.headers['Content-Type'].should include('charset=utf-8')
20
+ end
21
+
22
+ end
@@ -0,0 +1,94 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "JsonPrinter" do
4
+ describe ".render" do
5
+ it "should raise an error for invalid objects" do
6
+ lambda {
7
+ JsonPrinter.render(Object.new)
8
+ }.should raise_error
9
+ end
10
+
11
+ it "should render nil with null" do
12
+ JsonPrinter.render(nil).should == %{null}
13
+ end
14
+
15
+ it "should render true with true" do
16
+ JsonPrinter.render(true).should == %{true}
17
+ end
18
+
19
+ it "should render false with false" do
20
+ JsonPrinter.render(false).should == %{false}
21
+ end
22
+
23
+ it "should render JSON-escaped strings" do
24
+ JsonPrinter.render(%{foo&}).should == %{"foo\\u0026"}
25
+ end
26
+
27
+ it "should render symbols as strings" do
28
+ JsonPrinter.render(:foo).should == %{"foo"}
29
+ end
30
+
31
+ it "should render numbers" do
32
+ JsonPrinter.render(7).should == %{7}
33
+ end
34
+
35
+ it "should render times" do
36
+ t = Time.at(946702800).utc
37
+ JsonPrinter.render(t).should == "Sat Jan 01 05:00:00 UTC 2000"
38
+ end
39
+
40
+ it "should render arrays" do
41
+ JsonPrinter.render([:foo, :bar, :bat]).should ==
42
+ %{["foo",\n} <<
43
+ %{ "bar",\n} <<
44
+ %{ "bat"]}
45
+ end
46
+
47
+ it "should render arrays with repeated values" do
48
+ JsonPrinter.render([:foo, :bar, :foo]).should ==
49
+ %{["foo",\n} <<
50
+ %{ "bar",\n} <<
51
+ %{ "foo"]}
52
+ end
53
+
54
+ # TODO: would be nice to spec the actual output formatting
55
+
56
+ it "should render hashes" do
57
+ d = {"foo" => "bar", "biz" => "bat", "bing" => "bong"}
58
+ JSON.parse(JsonPrinter.render(d)).should == d
59
+ end
60
+
61
+ it "should render hashes with repeated values" do
62
+ d = {"foo" => "bar", "biz" => "bar", "bing" => "bar"}
63
+ JSON.parse(JsonPrinter.render(d)).should == d
64
+ end
65
+
66
+ describe "on compound data structures" do
67
+ before :each do
68
+ @d =
69
+ ["foo",
70
+ "bar",
71
+ ["biz",
72
+ "bang",
73
+ {"biz" => "bat",
74
+ "bang" => "yang"},
75
+ "zoo"],
76
+ "bat",
77
+ {"bang" => "str",
78
+ "comp" =>
79
+ ["foo",
80
+ "bar",
81
+ "bat"],
82
+ "hash" =>
83
+ {"from" => "to",
84
+ "next" => "best"}},
85
+ "fin",
86
+ "end"]
87
+ end
88
+
89
+ it "should render" do
90
+ JSON.parse(JsonPrinter.render(@d)).should == @d
91
+ end
92
+ end
93
+ end
94
+ end
data/spec/service_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe Neo4jr::Service do
4
-
4
+
5
5
  it "should be able to create a node" do
6
6
  post '/nodes', 'some_property=a_value&type=person'
7
7
  node = response_to_ruby
data/spec/spec_helper.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
- $LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'neo4jr-simple', 'lib'))
5
- require 'neo4jr-simple'
6
-
7
4
  require 'neo4jr-social'
8
5
  require 'spec'
9
6
  require 'spec/autorun'
10
7
  require 'rack/test'
11
8
 
9
+ # Neo4jr::Configuration.database_path = File.join(File.expand_path(File.dirname(__FILE__)), 'test-imdb-database')
10
+ # puts Neo4jr::Configuration.database_path
11
+
12
12
  Spec::Runner.configure do |config|
13
13
  include Rack::Test::Methods
14
14
 
@@ -18,5 +18,5 @@ Spec::Runner.configure do |config|
18
18
 
19
19
  def response_to_ruby
20
20
  JSON.parse(last_response.body)
21
- end
21
+ end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4jr-social
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Deiters
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-26 00:00:00 -08:00
12
+ date: 2010-01-19 00:00:00 -08:00
13
13
  default_executable: start-neo4jr-social
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,16 +32,6 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: "0"
34
34
  version:
35
- - !ruby/object:Gem::Dependency
36
- name: neo4jr-simple
37
- type: :runtime
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 0.1.6
44
- version:
45
35
  - !ruby/object:Gem::Dependency
46
36
  name: sinatra
47
37
  type: :runtime
@@ -82,6 +72,7 @@ files:
82
72
  - VERSION
83
73
  - bin/start-neo4jr-social
84
74
  - config.ru
75
+ - config/warble.rb
85
76
  - examples/facebook.rb
86
77
  - examples/linkedin.rb
87
78
  - jetty-runtime/etc/jetty.xml
@@ -96,20 +87,17 @@ files:
96
87
  - jetty-runtime/start.jar
97
88
  - jetty-runtime/webapps/neo4jr-social.war
98
89
  - lib/neo4jr-social.rb
90
+ - lib/neo4jr-social/format_handler.rb
91
+ - lib/neo4jr-social/json_printer.rb
92
+ - lib/neo4jr-social/param_helper.rb
93
+ - lib/neo4jr-social/self_documentor.rb
99
94
  - lib/neo4jr-social/service.rb
100
- - lib/neo4jr-social/simple_cost_evaluator.rb
101
- - lib/neo4jr-social/version.rb
102
95
  - neo4jr-social.gemspec
96
+ - spec/format_handler_spec.rb
97
+ - spec/json_printer_spec.rb
103
98
  - spec/service_spec.rb
104
99
  - spec/spec.opts
105
100
  - spec/spec_helper.rb
106
- - tmp/war/WEB-INF/lib/jruby-core-1.4.0.jar
107
- - tmp/war/WEB-INF/lib/jruby-rack-0.9.5.jar
108
- - tmp/war/WEB-INF/lib/jruby-stdlib-1.4.0.jar
109
- - tmp/war/WEB-INF/lib/neo4jr-social.rb
110
- - tmp/war/WEB-INF/lib/neo4jr-social/service.rb
111
- - tmp/war/WEB-INF/lib/neo4jr-social/version.rb
112
- - tmp/war/WEB-INF/web.xml
113
101
  has_rdoc: true
114
102
  homepage: http://github.com/mdeiters/neo4jr-social
115
103
  licenses: []
@@ -139,6 +127,8 @@ signing_key:
139
127
  specification_version: 3
140
128
  summary: A self-containted and lightweight REST interface to Neo4j using JRuby.
141
129
  test_files:
130
+ - spec/format_handler_spec.rb
131
+ - spec/json_printer_spec.rb
142
132
  - spec/service_spec.rb
143
133
  - spec/spec_helper.rb
144
134
  - examples/facebook.rb
@@ -1,9 +0,0 @@
1
- module Neo4jr
2
- class SimpleEvaluator
3
- include org.neo4j.graphalgo.shortestpath.CostEvaluator
4
-
5
- def getCost(relationship, backwards)
6
- 1.0
7
- end
8
- end
9
- end
@@ -1,3 +0,0 @@
1
- module Neo4jr::Social
2
- VERSION = File.read(File.expand_path(File.dirname(__FILE__) + "/../../VERSION")) unless defined?(Neo4jr::Social::VERSION)
3
- end
@@ -1,97 +0,0 @@
1
- module Neo4jr
2
- class Service < Sinatra::Base
3
-
4
- get '/info' do
5
- Neo4jr::DB.stats.to_json
6
- end
7
-
8
- get '/nodes' do
9
- nodes = Neo4jr::DB.execute do |neo|
10
- nodes = neo.all_nodes.map{|m| m.to_hash }
11
- end
12
- nodes.to_json
13
- end
14
-
15
- post '/nodes' do
16
- node = Neo4jr::DB.execute do |neo|
17
- node = neo.create_node(params)
18
- end
19
- node.to_hash.to_json
20
- end
21
-
22
- get '/nodes/:node_id' do
23
- Neo4jr::DB.getNodeById(params.delete('node_id')).to_json
24
- end
25
-
26
- put '/nodes/:node_id' do
27
- node = Neo4jr::DB.execute do |neo|
28
- node = neo.getNodeById(params.delete('node_id'))
29
- node.update_properties(params)
30
- end
31
- node.to_hash.to_json
32
- end
33
-
34
- delete '/nodes/:node_id' do
35
- Neo4jr::DB.execute do |neo|
36
- node = neo.getNodeById(params['node_id'])
37
- node.delete
38
- end
39
- end
40
-
41
- get '/nodes/:node_id/relationships' do
42
- relationships = Neo4jr::DB.execute do |neo|
43
- node = neo.getNodeById(params.delete('node_id'))
44
- if relationship_type = params.delete('type')
45
- relationship_type = RelationshipType.instance(relationship_type)
46
- node.getRelationships(relationship_type.to_a).hashify_objects
47
- else
48
- node.getRelationships.hashify_objects
49
- end
50
- end
51
- relationships.to_json
52
- end
53
-
54
- post '/nodes/:node_id/relationships' do
55
- relationships = Neo4jr::DB.execute do |neo|
56
- node = neo.getNodeById(params.delete('node_id'))
57
- to_node = neo.getNodeById(params.delete('to'))
58
- relationship_type = RelationshipType.instance(params.delete('type'))
59
- relationship = node.create_relationship_to to_node, relationship_type
60
- relationship.update_properties(params)
61
- node.getRelationships(relationship_type.to_a).hashify_objects
62
- end
63
- relationships.to_json
64
- end
65
-
66
- #optional direction & depth
67
- get '/nodes/:node_id/path' do
68
- paths = Neo4jr::DB.execute do |neo|
69
- relationship = Neo4jr::RelationshipType.instance(params.delete('type'))
70
- start_node = neo.getNodeById(params.delete('node_id'))
71
- end_node = neo.getNodeById(params.delete('to'))
72
- depth = params.delete('depth') || 2
73
- direction = Neo4jr::Direction.from_string(params.delete('direction') || 'both')
74
- shortest_path = AllSimplePaths.new(start_node, end_node, depth.to_i, direction, relationship.to_a)
75
- paths = shortest_path.getPaths
76
- paths.map{|p| p.map{|n| n.to_hash }}
77
- end
78
- paths.to_json
79
- end
80
-
81
- #optional
82
- get '/nodes/:node_id/recommendations' do
83
- suggestions = Neo4jr::DB.execute do |neo|
84
- relationship = Neo4jr::RelationshipType.incoming(params.delete('type'))
85
- start_node = neo.getNodeById(params.delete('node_id'))
86
- level = (params.delete('level') || 1).to_i
87
- order = Order::BREADTH_FIRST
88
- return_when = Return.when do |current_position|
89
- current_position.depth > level
90
- end
91
- traverser = start_node.traverse(order, Stop.at(level + 1), return_when, relationship)
92
- traverser.map{|node| node.to_hash }
93
- end
94
- suggestions.to_json
95
- end
96
- end
97
- end
@@ -1,3 +0,0 @@
1
- module Neo4jr::Social
2
- VERSION = File.read(File.expand_path(File.dirname(__FILE__) + "/../../VERSION")) unless defined?(Neo4jr::Social::VERSION)
3
- end
@@ -1,14 +0,0 @@
1
- $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
2
-
3
- include Java
4
-
5
- require 'rubygems'
6
- gem 'sinatra'
7
- gem 'json_pure'
8
- gem 'neo4jr-simple'
9
-
10
- require 'sinatra'
11
- require 'json'
12
- require 'neo4jr-simple'
13
- require 'neo4jr-social/service'
14
-
@@ -1,38 +0,0 @@
1
- <!DOCTYPE web-app PUBLIC
2
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
3
- "http://java.sun.com/dtd/web-app_2_3.dtd">
4
- <web-app>
5
-
6
- <context-param>
7
- <param-name>rails.env</param-name>
8
- <param-value>production</param-value>
9
- </context-param>
10
-
11
- <context-param>
12
- <param-name>public.root</param-name>
13
- <param-value>/</param-value>
14
- </context-param>
15
-
16
- <context-param>
17
- <param-name>rackup</param-name>
18
- <param-value>require 'lib/neo4jr-social'
19
-
20
- run Neo4jr::Service</param-value>
21
- </context-param>
22
-
23
-
24
- <filter>
25
- <filter-name>RackFilter</filter-name>
26
- <filter-class>org.jruby.rack.RackFilter</filter-class>
27
- </filter>
28
- <filter-mapping>
29
- <filter-name>RackFilter</filter-name>
30
- <url-pattern>/*</url-pattern>
31
- </filter-mapping>
32
-
33
- <listener>
34
- <listener-class>org.jruby.rack.RackServletContextListener</listener-class>
35
- </listener>
36
-
37
-
38
- </web-app>