keymaker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in keymaker.gemspec
4
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Rogelio J. Samour
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Keymaker
2
+
3
+ ## NOTICE OF WORK IN PROGRESS
4
+
5
+ A multi-layer REST API Ruby wrapper for the neo4j graph database.
6
+
7
+ ```
8
+ Oracle: Our time is up. Listen to me, Neo.
9
+ You can save Zion if you reach The Source,
10
+ but to do that you will need the Keymaker.
11
+ Neo: The Keymaker?
12
+ ```
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'keymaker'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install keymaker
27
+
28
+ ## Usage
29
+
30
+ ### Configuration
31
+
32
+ ```
33
+ Coming soon
34
+ ```
35
+
36
+ ### Nodes
37
+
38
+ ```
39
+ Coming soon
40
+ ```
41
+
42
+ ### Relationships
43
+
44
+ ```
45
+ Coming soon
46
+ ```
47
+
48
+ ### Indices
49
+
50
+ ```
51
+ Coming soon
52
+ ```
53
+
54
+ ### Querying
55
+
56
+ ```
57
+ Coming soon
58
+ ```
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 2. Create a feature branch (`git checkout -b my_new_feature`)
64
+ 3. Write passing tests!
65
+ 3. Commit your changes (`git commit -v`)
66
+ 4. Push to the branch (`git push origin my_new_feature`)
67
+ 5. Create new Pull Request
68
+
69
+ ## TODO:
70
+
71
+ - Test coverage
72
+ - Helper rake tasks for development
73
+ - Contributing documentation (installing neo4j, etc).
74
+ - Documentation
75
+
76
+ ## Acknowledgements
77
+
78
+ - Avdi Grimm
79
+ - Micah Cooper
80
+ - Stephen Caudill
81
+
82
+ ## Copyright
83
+ Copyright (c) 2012 [Rogelio J. Samour](mailto:rogelio@therubymug.com)
84
+ See [LICENSE][] for details.
85
+
86
+ [license]: https://github.com/therubymug/keymaker/blob/master/LICENSE.md
data/Rakefile ADDED
@@ -0,0 +1,123 @@
1
+
2
+ #############################################################################
3
+ #
4
+ # Helper functions
5
+ #
6
+ #############################################################################
7
+
8
+ def name
9
+ @name ||= Dir['*.gemspec'].first.split('.').first
10
+ end
11
+
12
+ def version
13
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
14
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
15
+ end
16
+
17
+ def date
18
+ Date.today.to_s
19
+ end
20
+
21
+ def gemspec_file
22
+ "#{name}.gemspec"
23
+ end
24
+
25
+ def gem_file
26
+ "#{name}-#{version}.gem"
27
+ end
28
+
29
+ def replace_header(head, header_name)
30
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
31
+ end
32
+
33
+ #############################################################################
34
+ #
35
+ # Standard tasks
36
+ #
37
+ #############################################################################
38
+
39
+ require 'rspec'
40
+ require 'rspec/core/rake_task'
41
+
42
+ desc "Run all specs"
43
+ task RSpec::Core::RakeTask.new('spec')
44
+
45
+ task :default => "spec"
46
+
47
+ desc "Open an irb session preloaded with this library"
48
+ task :console do
49
+ sh "irb -rubygems -r ./lib/#{name}.rb"
50
+ end
51
+
52
+ #############################################################################
53
+ #
54
+ # Custom tasks (add your own tasks here)
55
+ #
56
+ #############################################################################
57
+
58
+
59
+ #############################################################################
60
+ #
61
+ # Packaging tasks
62
+ #
63
+ #############################################################################
64
+
65
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
66
+ task :release => :build do
67
+ unless `git branch` =~ /^\* master$/
68
+ puts "You must be on the master branch to release!"
69
+ exit!
70
+ end
71
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
72
+ sh "git tag v#{version}"
73
+ sh "git push origin master"
74
+ sh "git push origin v#{version}"
75
+ sh "gem push pkg/#{name}-#{version}.gem"
76
+ end
77
+
78
+ desc "Build #{gem_file} into the pkg directory"
79
+ task :build => :gemspec do
80
+ sh "mkdir -p pkg"
81
+ sh "gem build #{gemspec_file}"
82
+ sh "mv #{gem_file} pkg"
83
+ end
84
+
85
+ desc "Generate #{gemspec_file}"
86
+ task :gemspec => :validate do
87
+ # read spec file and split out manifest section
88
+ spec = File.read(gemspec_file)
89
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
90
+
91
+ # replace name version and date
92
+ replace_header(head, :name)
93
+ replace_header(head, :version)
94
+ replace_header(head, :date)
95
+
96
+ # determine file list from git ls-files
97
+ files = `git ls-files`.
98
+ split("\n").
99
+ sort.
100
+ reject { |file| file =~ /^\./ }.
101
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
102
+ map { |file| " #{file}" }.
103
+ join("\n")
104
+
105
+ # piece file back together and write
106
+ manifest = " s.files = %w[\n#{files}\n ]\n"
107
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
108
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
109
+ puts "Updated #{gemspec_file}"
110
+ end
111
+
112
+ desc "Validate #{gemspec_file}"
113
+ task :validate do
114
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
115
+ unless libfiles.empty?
116
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
117
+ exit!
118
+ end
119
+ unless Dir['VERSION*'].empty?
120
+ puts "A `VERSION` file at root level violates Gem best practices."
121
+ exit!
122
+ end
123
+ end
data/keymaker.gemspec ADDED
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+ ## This is the rakegem gemspec template. Make sure you read and understand
3
+ ## all of the comments. Some sections require modification, and others can
4
+ ## be deleted if you don't need them. Once you understand the contents of
5
+ ## this file, feel free to delete any comments that begin with two hash marks.
6
+ ## You can find comprehensive Gem::Specification documentation, at
7
+ ## http://docs.rubygems.org/read/chapter/20
8
+ Gem::Specification.new do |s|
9
+ s.specification_version = 2 if s.respond_to? :specification_version=
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.rubygems_version = '1.3.5'
12
+
13
+ ## Leave these as is they will be modified for you by the rake gemspec task.
14
+ ## If your rubyforge_project name is different, then edit it and comment out
15
+ ## the sub! line in the Rakefile
16
+ s.name = 'keymaker'
17
+ s.version = '0.0.1'
18
+ s.date = '2012-06-06'
19
+
20
+ ## Make sure your summary is short. The description may be as long
21
+ ## as you like.
22
+ s.description = %q{A multi-layer REST API wrapper for neo4j.}
23
+ s.summary = %q{A multi-layer REST API wrapper for neo4j.}
24
+
25
+ ## List the primary authors. If there are a bunch of authors, it's probably
26
+ ## better to set the email to an email list or something. If you don't have
27
+ ## a custom homepage, consider using your GitHub URL or the like.
28
+ s.authors = ["Rogelio J. Samour", "Travis L. Anderson"]
29
+ s.email = ["rogelio@therubymug.com", "travis@travisleeanderson.com"]
30
+ s.homepage = "https://github.com/therubymug/keymaker"
31
+
32
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
33
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
34
+ s.require_paths = %w[lib]
35
+
36
+ ## Specify any RDoc options here. You'll want to add your README and
37
+ ## LICENSE files to the extra_rdoc_files list.
38
+ ## s.rdoc_options = ["--charset=UTF-8"]
39
+ s.extra_rdoc_files = %w[README.md LICENSE.md]
40
+
41
+ ## List your runtime dependencies here. Runtime dependencies are those
42
+ ## that are needed for an end user to actually USE your code.
43
+ ## s.add_dependency('DEPNAME', [">= 1.1.0", "< 2.0.0"])
44
+ s.add_dependency 'addressable'
45
+ s.add_dependency 'faraday'
46
+ s.add_dependency 'faraday_middleware'
47
+ s.add_dependency 'activemodel'
48
+
49
+ ## List your development dependencies here. Development dependencies are
50
+ ## those that are only needed during development
51
+ ## s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
52
+ s.add_development_dependency 'rake'
53
+ s.add_development_dependency 'rspec'
54
+ s.add_development_dependency 'ruby-debug19'
55
+
56
+ ## Leave this section as-is. It will be automatically generated from the
57
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
58
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
59
+ # = MANIFEST =
60
+ s.files = %w[
61
+ Gemfile
62
+ LICENSE.md
63
+ README.md
64
+ Rakefile
65
+ keymaker.gemspec
66
+ keymaker_integration_spec.rb
67
+ lib/keymaker.rb
68
+ lib/keymaker/add_node_to_index_request.rb
69
+ lib/keymaker/batch_get_nodes_request.rb
70
+ lib/keymaker/configuration.rb
71
+ lib/keymaker/create_node_request.rb
72
+ lib/keymaker/create_relationship_request.rb
73
+ lib/keymaker/delete_relationship_request.rb
74
+ lib/keymaker/execute_cypher_request.rb
75
+ lib/keymaker/execute_gremlin_request.rb
76
+ lib/keymaker/indexing.rb
77
+ lib/keymaker/node.rb
78
+ lib/keymaker/path_traverse_request.rb
79
+ lib/keymaker/remove_node_from_index_request.rb
80
+ lib/keymaker/request.rb
81
+ lib/keymaker/response.rb
82
+ lib/keymaker/serialization.rb
83
+ lib/keymaker/service.rb
84
+ lib/keymaker/update_node_properties_request.rb
85
+ spec/lib/keymaker_integration_spec.rb
86
+ spec/spec_helper.rb
87
+ spec/support/keymaker.rb
88
+ ]
89
+ # = MANIFEST =
90
+
91
+ ## Test files will be grabbed from the file list. Make sure the path glob
92
+ ## matches what you actually use.
93
+ s.test_files = s.files.grep(%r{^spec/})
94
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe Keymaker do
4
+
5
+ include_context "John and Sarah nodes"
6
+
7
+ context "indeces" do
8
+ include_context "John and Sarah indexed nodes"
9
+
10
+ context "given a bad port number" do
11
+
12
+ let(:url) { john_node_url.dup.gsub("7475", "49152") }
13
+
14
+ after { service.connection = connection }
15
+
16
+ def do_it
17
+ connection.get(url)
18
+ end
19
+
20
+ it "raises an error" do
21
+ expect { do_it }.to raise_error
22
+ end
23
+
24
+ end
25
+
26
+ context "given an explicit connection" do
27
+
28
+ let(:url) { john_node_url }
29
+
30
+ before { service.connection = test_connection }
31
+ after { service.connection = connection }
32
+
33
+ def do_it
34
+ service.connection.get(url)
35
+ end
36
+
37
+ it "uses the connection for requests" do
38
+ faraday_stubs.get(Addressable::URI.parse(url).path) do
39
+ [200, {}, "{}"]
40
+ end
41
+ do_it
42
+ faraday_stubs.verify_stubbed_calls
43
+ end
44
+
45
+ end
46
+
47
+ describe "#add_node_to_index(index_name, key, value, node_id)" do
48
+
49
+ def do_it
50
+ service.add_node_to_index(:users, :email, email, node_id)
51
+ end
52
+
53
+ context "given existing values" do
54
+
55
+ let(:email) { john_email }
56
+ let(:node_id) { john_node_id }
57
+
58
+ it "adds the node to the index" do
59
+ do_it
60
+ connection.get(index_query_for_john_url).body.should be_present
61
+ end
62
+
63
+ it "returns a status of 201" do
64
+ do_it.status.should == 201
65
+ end
66
+
67
+ end
68
+
69
+ context "given an invalid node id" do
70
+
71
+ let(:email) { john_email }
72
+ let(:node_id) { -22 }
73
+
74
+ it "returns a 500 status" do
75
+ do_it.status.should == 500
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+
82
+ describe "#remove_node_from_index(index_name, key, value, node_id)" do
83
+
84
+ def do_it
85
+ service.remove_node_from_index(:users, :email, email, node_id)
86
+ end
87
+
88
+ context "given existing values" do
89
+
90
+ let(:email) { john_email }
91
+ let(:node_id) { john_node_id }
92
+
93
+ it "removes the node from the index" do
94
+ do_it
95
+ connection.get(index_query_for_john_url).body.should be_empty
96
+ end
97
+
98
+ it "returns a status of 204" do
99
+ do_it.status.should == 204
100
+ end
101
+
102
+ it "keeps the other node indices" do
103
+ do_it
104
+ connection.get(index_query_for_sarah_url).body.should_not be_empty
105
+ end
106
+
107
+ end
108
+
109
+ context "given unmatched values" do
110
+
111
+ let(:email) { "unknown@example.com" }
112
+ let(:node_id) { -22 }
113
+
114
+ it "returns a 404 status" do
115
+ do_it.status.should == 404
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+ end
122
+
123
+ describe "#execute_query" do
124
+
125
+ def do_it
126
+ service.execute_query("START user=node:users(email={email} RETURN user", email: john_email)
127
+ end
128
+
129
+ context "given existing values" do
130
+
131
+ before { service.add_node_to_index(:users, :email, john_email, john_node_id) }
132
+
133
+ it "performs the cypher query and responds" do
134
+ do_it.should be_present
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
141
+ context "nodes" do
142
+
143
+ include_context "Keymaker connections"
144
+
145
+ describe "#create_node" do
146
+
147
+ let(:properties) { { first_name: "john", last_name: "connor", email: "john@resistance.net" } }
148
+
149
+ def do_it
150
+ new_node_id = service.create_node(properties).neo4j_id
151
+ connection.get("/db/data/node/#{new_node_id}/properties").body
152
+ end
153
+
154
+ it "creates a node with properties" do
155
+ do_it.should == {"first_name"=>"john", "email"=>"john@resistance.net", "last_name"=>"connor"}
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+
162
+ context "relationships" do
163
+
164
+ include_context "Keymaker connections"
165
+
166
+ describe "#create_relationship" do
167
+
168
+ def do_it
169
+ service.create_relationship(:loves, john_node_id, sarah_node_id).neo4j_id
170
+ connection.get("/db/data/node/#{john_node_id}/relationships/all/loves").body.first
171
+ end
172
+
173
+ it "creates the relationship between the two nodes" do
174
+ do_it["start"].should == john_node_url
175
+ do_it["end"].should == sarah_node_url
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+
182
+ end