keymaker 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/README.md +71 -11
  2. data/Rakefile +1 -1
  3. data/keymaker.gemspec +46 -15
  4. data/lib/keymaker.rb +25 -12
  5. data/lib/keymaker/configuration.rb +4 -0
  6. data/lib/keymaker/errors.rb +22 -0
  7. data/lib/keymaker/match_method.rb +24 -0
  8. data/lib/keymaker/request.rb +2 -1
  9. data/lib/keymaker/{add_node_to_index_request.rb → requests/add_node_to_index_request.rb} +0 -0
  10. data/lib/keymaker/requests/batch_get_nodes_request.rb +24 -0
  11. data/lib/keymaker/requests/batch_request.rb +18 -0
  12. data/lib/keymaker/{create_node_request.rb → requests/create_node_request.rb} +0 -0
  13. data/lib/keymaker/{create_relationship_request.rb → requests/create_relationship_request.rb} +0 -0
  14. data/lib/keymaker/requests/delete_node_request.rb +18 -0
  15. data/lib/keymaker/{delete_relationship_request.rb → requests/delete_relationship_request.rb} +0 -0
  16. data/lib/keymaker/{execute_cypher_request.rb → requests/execute_cypher_request.rb} +0 -0
  17. data/lib/keymaker/{execute_gremlin_request.rb → requests/execute_gremlin_request.rb} +0 -0
  18. data/lib/keymaker/requests/get_node_request.rb +16 -0
  19. data/lib/keymaker/requests/get_relationship_types_request.rb +18 -0
  20. data/lib/keymaker/{path_traverse_request.rb → requests/path_traverse_request.rb} +0 -0
  21. data/lib/keymaker/{remove_node_from_index_request.rb → requests/remove_node_from_index_request.rb} +0 -0
  22. data/lib/keymaker/requests/service_root_request.rb +11 -0
  23. data/lib/keymaker/{update_node_properties_request.rb → requests/update_node_properties_request.rb} +0 -0
  24. data/lib/keymaker/response.rb +8 -1
  25. data/lib/keymaker/service.rb +17 -43
  26. data/spec/cassettes/Keymaker_AddNodeToIndexRequest/returns_a_201_status_code.yml +204 -0
  27. data/spec/cassettes/Keymaker_AddNodeToIndexRequest/returns_application/json.yml +204 -0
  28. data/spec/cassettes/Keymaker_AddNodeToIndexRequest/returns_the_Neo4j_REST_API_starting_point_response_request.yml +204 -0
  29. data/spec/cassettes/Keymaker_BatchRequest/when_a_resource_is_not_found/raises_BatchRequestError.yml +120 -0
  30. data/spec/cassettes/Keymaker_BatchRequest/when_to_and_method_are_not_set/raises_BatchRequestError.yml +106 -0
  31. data/spec/cassettes/Keymaker_BatchRequest/with_valid_options/returns_a_200_status_code.yml +129 -0
  32. data/spec/cassettes/Keymaker_BatchRequest/with_valid_options/runs_the_commands_and_returns_their_respective_results.yml +129 -0
  33. data/spec/cassettes/Keymaker_GetNodeRequest/with_a_non-existent_node_id/raises_ResourceNotFound.yml +101 -0
  34. data/spec/cassettes/Keymaker_GetNodeRequest/with_an_empty_node_id/raises_ClientError.yml +111 -0
  35. data/spec/cassettes/Keymaker_GetRelationshipTypesRequest/with_existing_relationships/returns_a_unique_array_of_relationship_types.yml +220 -0
  36. data/spec/cassettes/Keymaker_ServiceRootRequest/returns_a_200_status_code.yml +105 -0
  37. data/spec/cassettes/Keymaker_ServiceRootRequest/returns_application/json.yml +105 -0
  38. data/spec/cassettes/Keymaker_ServiceRootRequest/returns_the_Neo4j_REST_API_starting_point_response_request.yml +105 -0
  39. data/spec/{keymaker/configuration_spec.rb → configuration_spec.rb} +0 -0
  40. data/spec/keymaker/requests/add_node_to_index_request_spec.rb +41 -0
  41. data/spec/keymaker/requests/batch_get_nodes_request_spec.rb +23 -0
  42. data/spec/keymaker/requests/batch_request_spec.rb +115 -0
  43. data/spec/keymaker/requests/delete_node_request_spec.rb +37 -0
  44. data/spec/keymaker/requests/get_node_request_spec.rb +24 -0
  45. data/spec/keymaker/requests/get_relationship_types_request_spec.rb +17 -0
  46. data/spec/keymaker/requests/service_root_request_spec.rb +35 -0
  47. data/spec/{keymaker/service_spec.rb → service_spec.rb} +0 -0
  48. data/spec/support/vcr.rb +8 -0
  49. metadata +116 -19
  50. data/lib/keymaker/batch_get_nodes_request.rb +0 -19
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Keymaker
2
2
 
3
- ## NOTICE OF WORK IN PROGRESS
4
-
5
- A multi-layer REST API Ruby wrapper for the neo4j graph database.
3
+ A multi-layer REST API Ruby wrapper for the Neo4j graph database built on top of [Faraday][].
6
4
 
7
5
  ```
8
6
  Oracle: Our time is up. Listen to me, Neo.
@@ -13,24 +11,86 @@ Neo: The Keymaker?
13
11
 
14
12
  ## Installation
15
13
 
16
- Add this line to your application's Gemfile:
14
+ Install and start the Neo4j server:
17
15
 
18
- gem 'keymaker'
16
+ ```ruby
17
+ rake neo4j:install
18
+ rake neo4j:start
19
+ # optionally for testing
20
+ rake neo4j:install RAILS_ENV=test
21
+ rake neo4j:start RAILS_ENV=test
22
+ ```
19
23
 
20
- And then execute:
24
+ Add this line to your application's Gemfile:
21
25
 
22
- $ bundle
26
+ ```ruby
27
+ gem 'keymaker'
28
+ ```
23
29
 
24
- Or install it yourself as:
30
+ And then execute:
25
31
 
26
- $ gem install keymaker
32
+ ```
33
+ $ bundle
34
+ ```
27
35
 
28
36
  ## Usage
29
37
 
30
38
  ### Configuration
31
39
 
40
+ Create a `config/neo4j.yml` file:
41
+
42
+ ```ruby
43
+ development:
44
+ server: localhost
45
+ port: 7474
46
+ test:
47
+ server: localhost
48
+ port: 7475
32
49
  ```
33
- Coming soon
50
+
51
+ Then, create a Rails initializer `config/initializers/keymaker.rb`:
52
+
53
+ ```ruby
54
+ if Rails.env.development? || Rails.env.test?
55
+ database_config = YAML::load_file('config/neo4j.yml')
56
+ Keymaker.configure do |c|
57
+ c.server = database_config["#{Rails.env}"]['server']
58
+ c.port = database_config["#{Rails.env}"]['port']
59
+ end
60
+ else
61
+ # Heroku neo4j add-on
62
+ Keymaker.configure do |c|
63
+ c.server = ENV['NEO4J_HOST']
64
+ c.port = ENV['NEO4J_PORT'].to_i
65
+ c.username = ENV['NEO4J_LOGIN']
66
+ c.password = ENV['NEO4J_PASSWORD']
67
+ end
68
+ end
69
+ ```
70
+
71
+ ### Low-level REST API Calls
72
+
73
+ ```ruby
74
+
75
+ Keymaker.configure do |c|
76
+ c.server = "localhost"
77
+ c.port = 7474
78
+ end
79
+
80
+ ## Create a node ##
81
+
82
+ response = Keymaker.service.create_node_request({:name => 'John Connor', :catch_phrase => 'No problemo'})
83
+
84
+ ## Update node properties ##
85
+
86
+ ## Delete a node ##
87
+
88
+ ## Create a relationship ##
89
+
90
+ ## Update relationship properties ##
91
+
92
+ ## Delete a relationship ##
93
+
34
94
  ```
35
95
 
36
96
  ### Nodes
@@ -69,7 +129,6 @@ Coming soon
69
129
  ## TODO:
70
130
 
71
131
  - Test coverage
72
- - Helper rake tasks for development
73
132
  - Contributing documentation (installing neo4j, etc).
74
133
  - Documentation
75
134
 
@@ -85,3 +144,4 @@ Copyright (c) 2012 [Rogelio J. Samour](mailto:rogelio@therubymug.com)
85
144
  See [LICENSE][] for details.
86
145
 
87
146
  [license]: https://github.com/therubymug/keymaker/blob/master/LICENSE.md
147
+ [faraday]: https://github.com/technoweenie/faraday
data/Rakefile CHANGED
@@ -127,7 +127,7 @@ end
127
127
  #
128
128
  #############################################################################
129
129
 
130
- KEYMAKER_ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
130
+ KEYMAKER_ROOT = File.expand_path(File.dirname(__FILE__))
131
131
  KEYMAKER_TMP_DIR = File.expand_path(File.join(KEYMAKER_ROOT, "tmp"))
132
132
  NEO4J_INSTALL_DIR = ENV['NEO4J_INSTALL_DIR'] || File.expand_path(File.join(KEYMAKER_TMP_DIR, "keymaker_development"))
133
133
  NEO4J_PORT = ENV['NEO4J_PORT'] || '7477' # Don't clobber standard neo4j ports 7474 or 7475 for development
data/keymaker.gemspec CHANGED
@@ -14,8 +14,8 @@ Gem::Specification.new do |s|
14
14
  ## If your rubyforge_project name is different, then edit it and comment out
15
15
  ## the sub! line in the Rakefile
16
16
  s.name = 'keymaker'
17
- s.version = '0.0.7'
18
- s.date = '2012-06-15'
17
+ s.version = '0.0.8'
18
+ s.date = '2012-07-19'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
21
21
  ## as you like.
@@ -41,17 +41,20 @@ Gem::Specification.new do |s|
41
41
  ## List your runtime dependencies here. Runtime dependencies are those
42
42
  ## that are needed for an end user to actually USE your code.
43
43
  ## s.add_dependency('DEPNAME', [">= 1.1.0", "< 2.0.0"])
44
+ s.add_dependency 'activemodel'
45
+ s.add_dependency 'activesupport'
44
46
  s.add_dependency 'addressable'
45
47
  s.add_dependency 'faraday'
46
48
  s.add_dependency 'faraday_middleware'
47
- s.add_dependency 'activemodel'
48
49
 
49
50
  ## List your development dependencies here. Development dependencies are
50
51
  ## those that are only needed during development
51
52
  ## s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
53
+ s.add_development_dependency 'fakeweb'
52
54
  s.add_development_dependency 'rake'
53
55
  s.add_development_dependency 'rspec'
54
56
  s.add_development_dependency 'ruby-debug19'
57
+ s.add_development_dependency 'vcr'
55
58
 
56
59
  ## Leave this section as-is. It will be automatically generated from the
57
60
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
@@ -64,30 +67,58 @@ Gem::Specification.new do |s|
64
67
  Rakefile
65
68
  keymaker.gemspec
66
69
  lib/keymaker.rb
67
- lib/keymaker/add_node_to_index_request.rb
68
- lib/keymaker/batch_get_nodes_request.rb
69
70
  lib/keymaker/configuration.rb
70
- lib/keymaker/create_node_request.rb
71
- lib/keymaker/create_relationship_request.rb
72
- lib/keymaker/delete_relationship_request.rb
73
- lib/keymaker/execute_cypher_request.rb
74
- lib/keymaker/execute_gremlin_request.rb
71
+ lib/keymaker/errors.rb
75
72
  lib/keymaker/indexing.rb
73
+ lib/keymaker/match_method.rb
76
74
  lib/keymaker/node.rb
77
- lib/keymaker/path_traverse_request.rb
78
75
  lib/keymaker/rails_tasks.rb
79
76
  lib/keymaker/railtie.rb
80
- lib/keymaker/remove_node_from_index_request.rb
81
77
  lib/keymaker/request.rb
78
+ lib/keymaker/requests/add_node_to_index_request.rb
79
+ lib/keymaker/requests/batch_get_nodes_request.rb
80
+ lib/keymaker/requests/batch_request.rb
81
+ lib/keymaker/requests/create_node_request.rb
82
+ lib/keymaker/requests/create_relationship_request.rb
83
+ lib/keymaker/requests/delete_node_request.rb
84
+ lib/keymaker/requests/delete_relationship_request.rb
85
+ lib/keymaker/requests/execute_cypher_request.rb
86
+ lib/keymaker/requests/execute_gremlin_request.rb
87
+ lib/keymaker/requests/get_node_request.rb
88
+ lib/keymaker/requests/get_relationship_types_request.rb
89
+ lib/keymaker/requests/path_traverse_request.rb
90
+ lib/keymaker/requests/remove_node_from_index_request.rb
91
+ lib/keymaker/requests/service_root_request.rb
92
+ lib/keymaker/requests/update_node_properties_request.rb
82
93
  lib/keymaker/response.rb
83
94
  lib/keymaker/serialization.rb
84
95
  lib/keymaker/service.rb
85
- lib/keymaker/update_node_properties_request.rb
86
- spec/keymaker/configuration_spec.rb
87
- spec/keymaker/service_spec.rb
96
+ spec/cassettes/Keymaker_AddNodeToIndexRequest/returns_a_201_status_code.yml
97
+ spec/cassettes/Keymaker_AddNodeToIndexRequest/returns_application/json.yml
98
+ spec/cassettes/Keymaker_AddNodeToIndexRequest/returns_the_Neo4j_REST_API_starting_point_response_request.yml
99
+ spec/cassettes/Keymaker_BatchRequest/when_a_resource_is_not_found/raises_BatchRequestError.yml
100
+ spec/cassettes/Keymaker_BatchRequest/when_to_and_method_are_not_set/raises_BatchRequestError.yml
101
+ spec/cassettes/Keymaker_BatchRequest/with_valid_options/returns_a_200_status_code.yml
102
+ spec/cassettes/Keymaker_BatchRequest/with_valid_options/runs_the_commands_and_returns_their_respective_results.yml
103
+ spec/cassettes/Keymaker_GetNodeRequest/with_a_non-existent_node_id/raises_ResourceNotFound.yml
104
+ spec/cassettes/Keymaker_GetNodeRequest/with_an_empty_node_id/raises_ClientError.yml
105
+ spec/cassettes/Keymaker_GetRelationshipTypesRequest/with_existing_relationships/returns_a_unique_array_of_relationship_types.yml
106
+ spec/cassettes/Keymaker_ServiceRootRequest/returns_a_200_status_code.yml
107
+ spec/cassettes/Keymaker_ServiceRootRequest/returns_application/json.yml
108
+ spec/cassettes/Keymaker_ServiceRootRequest/returns_the_Neo4j_REST_API_starting_point_response_request.yml
109
+ spec/configuration_spec.rb
110
+ spec/keymaker/requests/add_node_to_index_request_spec.rb
111
+ spec/keymaker/requests/batch_get_nodes_request_spec.rb
112
+ spec/keymaker/requests/batch_request_spec.rb
113
+ spec/keymaker/requests/delete_node_request_spec.rb
114
+ spec/keymaker/requests/get_node_request_spec.rb
115
+ spec/keymaker/requests/get_relationship_types_request_spec.rb
116
+ spec/keymaker/requests/service_root_request_spec.rb
88
117
  spec/keymaker_spec.rb
118
+ spec/service_spec.rb
89
119
  spec/spec_helper.rb
90
120
  spec/support/keymaker.rb
121
+ spec/support/vcr.rb
91
122
  ]
92
123
  # = MANIFEST =
93
124
 
data/lib/keymaker.rb CHANGED
@@ -1,22 +1,35 @@
1
1
  require 'faraday'
2
2
  require 'faraday_middleware'
3
3
  require 'active_model'
4
+ require 'active_support/core_ext/string/inflections'
4
5
 
5
- require 'keymaker/request'
6
+ require 'keymaker/match_method'
7
+ require 'keymaker/errors'
6
8
  require 'keymaker/response'
7
9
  require 'keymaker/configuration'
8
10
  require 'keymaker/service'
9
11
 
10
- require 'keymaker/add_node_to_index_request'
11
- require 'keymaker/batch_get_nodes_request'
12
- require 'keymaker/create_node_request'
13
- require 'keymaker/create_relationship_request'
14
- require 'keymaker/delete_relationship_request'
15
- require 'keymaker/execute_cypher_request'
16
- require 'keymaker/execute_gremlin_request'
17
- require 'keymaker/path_traverse_request'
18
- require 'keymaker/remove_node_from_index_request'
19
- require 'keymaker/update_node_properties_request'
12
+ require 'keymaker/request'
13
+
14
+ require 'keymaker/requests/batch_request'
15
+ require 'keymaker/requests/batch_get_nodes_request'
16
+
17
+ require 'keymaker/requests/create_node_request'
18
+ require 'keymaker/requests/delete_node_request'
19
+ require 'keymaker/requests/get_node_request'
20
+
21
+ require 'keymaker/requests/add_node_to_index_request'
22
+ require 'keymaker/requests/remove_node_from_index_request'
23
+ require 'keymaker/requests/update_node_properties_request'
24
+
25
+ require 'keymaker/requests/create_relationship_request'
26
+ require 'keymaker/requests/delete_relationship_request'
27
+ require 'keymaker/requests/get_relationship_types_request'
28
+
29
+ require 'keymaker/requests/execute_cypher_request'
30
+ require 'keymaker/requests/execute_gremlin_request'
31
+ require 'keymaker/requests/path_traverse_request'
32
+ require 'keymaker/requests/service_root_request'
20
33
 
21
34
  require 'keymaker/indexing'
22
35
  require 'keymaker/serialization'
@@ -26,7 +39,7 @@ require 'keymaker/railtie' if defined? Rails::Railtie
26
39
 
27
40
  module Keymaker
28
41
 
29
- VERSION = "0.0.7"
42
+ VERSION = "0.0.8"
30
43
 
31
44
  def self.service
32
45
  @service ||= Keymaker::Service.new(Keymaker::Configuration.new)
@@ -79,6 +79,10 @@ module Keymaker
79
79
  [data_directory, "relationship", relationship_id.to_s].join("/")
80
80
  end
81
81
 
82
+ def relationship_types_path
83
+ [data_directory, "relationship", "types"].join("/")
84
+ end
85
+
82
86
  def relationships_path_for_node(node_id)
83
87
  [node_path, node_id.to_s, "relationships"].join("/")
84
88
  end
@@ -0,0 +1,22 @@
1
+ require 'forwardable'
2
+
3
+ module Keymaker
4
+ class Error < StandardError; end
5
+ class HttpError < Error
6
+ extend Forwardable
7
+
8
+ attr_reader :response
9
+
10
+ def_delegator :response, :status
11
+
12
+ def initialize(response, message=response.status.to_s)
13
+ @response = response
14
+ super(message)
15
+ end
16
+ end
17
+ class ClientError < HttpError; end
18
+ class ConflictError < ClientError; end
19
+ class ResourceNotFound < ClientError; end
20
+ class ServerError < HttpError; end
21
+ class BatchRequestError < ServerError; end
22
+ end
@@ -0,0 +1,24 @@
1
+ # Avdi's magic sauce
2
+ module Keymaker
3
+ module MatchMethodMacros
4
+ def match_method(matcher, &method_body)
5
+ mod = Module.new do
6
+ define_method(:method_missing) do |method_name, *args|
7
+ if matcher === method_name.to_s
8
+ instance_exec(method_name, *args, &method_body)
9
+ else
10
+ super(method_name, *args)
11
+ end
12
+ end
13
+
14
+ define_method(:respond_to_missing?) do |method_name, include_private|
15
+ # Even though this is in the #respond_to_missing? hook we
16
+ # still need to call 'super' in case there are other included
17
+ # modules which also define #respond_to_missing?
18
+ (matcher === method_name) || super(method_name, include_private)
19
+ end
20
+ end
21
+ include mod
22
+ end
23
+ end
24
+ end
@@ -3,9 +3,9 @@ module Keymaker
3
3
 
4
4
  extend Forwardable
5
5
 
6
-
7
6
  def_delegator :config, :batch_node_path
8
7
  def_delegator :config, :batch_path
8
+ def_delegator :config, :data_directory_path
9
9
  def_delegator :config, :full_cypher_path
10
10
  def_delegator :config, :full_gremlin_path
11
11
  def_delegator :config, :node_full_index_path
@@ -16,6 +16,7 @@ module Keymaker
16
16
  def_delegator :config, :path_traverse_node_path
17
17
  def_delegator :config, :relationship_path
18
18
  def_delegator :config, :relationships_path_for_node
19
+ def_delegator :config, :relationship_types_path
19
20
 
20
21
  def_delegator :response, :body
21
22
  def_delegator :response, :status
@@ -0,0 +1,24 @@
1
+ module Keymaker
2
+
3
+ class BatchGetNodesRequest < BatchRequest
4
+
5
+ attr_accessor :node_ids
6
+
7
+ def initialize(service, node_ids)
8
+ self.config = service.config
9
+ self.node_ids = node_ids
10
+ self.service = service
11
+ self.opts = build_job_descriptions_collection
12
+ end
13
+
14
+ def build_job_descriptions_collection
15
+ [].tap do |batch_jobs|
16
+ node_ids.each_with_index do |node_id, job_id|
17
+ batch_jobs << {id: job_id, to: node_uri(node_id), method: "GET"}
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,18 @@
1
+ module Keymaker
2
+
3
+ class BatchRequest < Request
4
+
5
+ def submit
6
+ service.post(batch_path, opts).on_error do |response|
7
+ case response.status
8
+ when (400..499)
9
+ raise ClientError.new(response, response.body)
10
+ when (500..599)
11
+ raise BatchRequestError.new(response, response.body)
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ module Keymaker
2
+ class DeleteNodeRequest < Request
3
+ def submit
4
+ service.delete(node_uri(opts[:node_id])).on_error do |response|
5
+ case response.status
6
+ when 404
7
+ raise ResourceNotFound.new(response, response.body)
8
+ when 409
9
+ raise ConflictError.new(response, response.body)
10
+ when (400..499)
11
+ raise ClientError.new(response, response.body)
12
+ when (500..599)
13
+ raise ServerError.new(response, response.body)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end