keymaker 0.0.7 → 0.0.8

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 (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