keymaker 0.0.1

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