stretch 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  Gemfile.lock
7
7
  InstalledFiles
8
8
  _yardoc
9
+ bin/
9
10
  coverage
10
11
  doc/
11
12
  lib/bundler/man
@@ -14,4 +15,5 @@ rdoc
14
15
  spec/reports
15
16
  test/tmp
16
17
  test/version_tmp
18
+ vendor/gems
17
19
  tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ script: "./script/test"
3
+ gemfile: "this/does/not/exist"
4
+ rvm:
5
+ - "1.8.7"
6
+ - "1.9.3"
7
+ - "2.0.0"
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,14 @@
1
+ # Contributing Guidelines
2
+
3
+ Tests are run with `script/test`.
4
+
5
+ Test against the following Ruby versions:
6
+
7
+ * 1.8.7
8
+ * 1.9.3
9
+ * 2.0.0
10
+
11
+ Always work on a fork, on a feature branch.
12
+
13
+ Submit Pull Requests, with new tests for any changes.
14
+ Make sure the tests pass.
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Stretch
2
2
 
3
- Shhh -- a secret!
3
+ [![Build Status](https://travis-ci.org/wfarr/stretch.png?branch=master)](https://travis-ci.org/wfarr/stretch)
4
+ [![Code Climate Status](https://codeclimate.com/github/wfarr/stretch.png)](https://codeclimate.com/github/wfarr/stretch)
5
+
6
+ Elasticsearch client library written for people who like understandable
7
+ documentation and understandable code.
4
8
 
5
9
  ## Installation
6
10
 
@@ -18,12 +22,39 @@ Or install it yourself as:
18
22
 
19
23
  ## Usage
20
24
 
21
- You obviously can't use this yet.
25
+ ### Establishing a connection:
26
+
27
+ ``` ruby
28
+ $stretch = Stretch::Client.new :url => "http://127.0.0.1:9200/"
29
+ ```
30
+
31
+ ### Cluster and Index Health
32
+
33
+ ``` ruby
34
+ $stretch.cluster.health :timeout => '10s'
35
+ $stretch.index('tweets').health :wait_for_status => 'green'
36
+ ```
37
+
38
+ ### Cluster State
39
+
40
+ ``` ruby
41
+ $stretch.cluster.state
42
+ $stretch.cluster.state :filter_nodes => true
43
+ ```
44
+
45
+ ### Cluster and Index Settings
46
+
47
+ ``` ruby
48
+ $stretch.cluster.settings :persistent => {
49
+ "cluster.routing.allocation.node_concurrent_recoveries" => 4
50
+ }
51
+
52
+ $stretch.index('foo').settings :index => { :number_of_replicas => 2 }
53
+ ```
22
54
 
23
- ## Contributing
55
+ ### Opening and Closing Indices
24
56
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
57
+ ``` ruby
58
+ $stretch.index('foo').open!
59
+ $stretch.index('bar').close!
60
+ ```
data/lib/stretch.rb CHANGED
@@ -1,5 +1,7 @@
1
+ require "stretch/client"
1
2
  require "stretch/version"
2
3
 
3
4
  module Stretch
4
- # Your code goes here...
5
+ class InvalidScope < StandardError; end
6
+ class UnsupportedRequestMethod < StandardError; end
5
7
  end
@@ -0,0 +1,83 @@
1
+ require "stretch/connection"
2
+ require "stretch/uri_builder"
3
+
4
+ module Stretch
5
+ class Client
6
+ attr_reader :connection, :scope
7
+
8
+ def initialize options = {}
9
+ self.tap do
10
+ @scope = {
11
+ :cluster => false,
12
+ :index => nil
13
+ }
14
+
15
+ @connection = Stretch::Connection.new options
16
+ end
17
+ end
18
+
19
+ # Chainable methods
20
+ def cluster
21
+ self.tap do
22
+ scope[:cluster] = true
23
+ scope[:index] = nil
24
+ end
25
+ end
26
+
27
+ def index name
28
+ self.tap do
29
+ scope[:cluster] = false
30
+ scope[:index] = name
31
+ end
32
+ end
33
+
34
+ # End points
35
+ def health options = {}
36
+ with_scopes :cluster, :index do
37
+ connection.get build_path("/health"), options
38
+ end
39
+ end
40
+
41
+ def state options = {}
42
+ with_scopes :cluster do
43
+ connection.get build_path("/state"), options
44
+ end
45
+ end
46
+
47
+ def settings options = {}
48
+ with_scopes :cluster, :index do
49
+ if options.any?
50
+ connection.put build_path("/settings"), options
51
+ else
52
+ connection.get build_path("/settings")
53
+ end
54
+ end
55
+ end
56
+
57
+ def open!
58
+ with_scopes :index do
59
+ connection.post build_path("/_open")
60
+ end
61
+ end
62
+
63
+ def close!
64
+ with_scopes :index do
65
+ connection.post build_path("/_close")
66
+ end
67
+ end
68
+
69
+ private
70
+ def build_path path
71
+ Stretch::URIBuilder.build_from_scope scope, path
72
+ end
73
+
74
+ def with_scopes *scopes, &block
75
+ if scopes.any? {|s| scope.has_key?(s) && scope[s] }
76
+ yield
77
+ else
78
+ raise InvalidScope,
79
+ "Requires one of the following scopes: #{scopes.inspect}. #{scope.inspect} given."
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,67 @@
1
+ require "faraday"
2
+ require "multi_json"
3
+
4
+ module Stretch
5
+ class Connection
6
+ attr_reader :connection
7
+
8
+ REQUEST_METHODS = [ :get, :post, :put, :delete ].freeze
9
+
10
+ def initialize options = {}
11
+ @connection = Faraday.new(options)
12
+ end
13
+
14
+ def get path, options = {}
15
+ request :get, path, options
16
+ end
17
+
18
+ def post path, options = {}
19
+ request :post, path, options
20
+ end
21
+
22
+ def put path, options = {}
23
+ request :put, path, options
24
+ end
25
+
26
+ def delete path, options = {}
27
+ request :delete, path, options
28
+ end
29
+
30
+ private
31
+ def request method, path, options = {}
32
+ validate_request_method method
33
+
34
+ response = connection.send(method) do |request|
35
+ request.headers["Accept"] = "application/json"
36
+ request.path = path
37
+
38
+ case method
39
+ when :get
40
+ options.each { |k,v| request.params[k] = v }
41
+ when :post, :put
42
+ request.body = MultiJson.dump(options)
43
+ end
44
+ end
45
+
46
+ handle_response response
47
+ end
48
+
49
+ def validate_request_method method
50
+ unless REQUEST_METHODS.member? method
51
+ raise Stretch::UnsupportedRequestMethod, "#{method} is not supported!"
52
+ end
53
+ end
54
+
55
+ def handle_response response
56
+ if response.success?
57
+ if response.body.empty?
58
+ request :get, path
59
+ else
60
+ MultiJson.load response.body
61
+ end
62
+ else
63
+ response.error!
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,13 @@
1
+ module Stretch
2
+ class URIBuilder
3
+ def self.build_from_scope scope, path
4
+ path.gsub!(/\A\//, '')
5
+
6
+ if scope[:cluster]
7
+ "/_cluster/#{path}"
8
+ elsif scope[:index]
9
+ "/#{scope[:index]}/#{path}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Stretch
2
- VERSION = "0.0.0"
2
+ VERSION = "0.1.0"
3
3
  end
data/script/bootstrap ADDED
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ bundle install --path .bundle --binstubs .bundle/binstubs "$@"
data/script/test ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ root=$(cd "$(dirname $0)"/.. && pwd)
6
+
7
+ echo "Bundling..."
8
+ script/bootstrap
9
+
10
+ ruby -I"${root}/.bundle" -I"${root}/test" -e \
11
+ "(ARGV.empty? ? Dir['${root}/test/**/*_test.rb'] : ARGV).each { |f| load f }"
data/stretch.gemspec CHANGED
@@ -8,9 +8,11 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Stretch::VERSION
9
9
  spec.authors = ["Will Farrington"]
10
10
  spec.email = ["wfarr@github.com"]
11
- spec.description = %q{Shh, it's a secret}
12
- spec.summary = %q{Still seriously a secret}
13
- spec.homepage = ""
11
+ spec.description = %q{An Elasticsearch client library}
12
+ spec.summary = %q{It's not anywhere near complete at this time, but
13
+ the code is pretty all right allegedly.
14
+ }
15
+ spec.homepage = "https://github.com/wfarr/stretch"
14
16
  spec.license = "MIT"
15
17
 
16
18
  spec.files = `git ls-files`.split($/)
@@ -18,6 +20,11 @@ Gem::Specification.new do |spec|
18
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
21
  spec.require_paths = ["lib"]
20
22
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_dependency "faraday", "~> 0.8.7"
24
+ spec.add_dependency "multi_json", "~> 1.7.2"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.2"
27
+ spec.add_development_dependency "minitest", "~> 4.0"
28
+ spec.add_development_dependency "pry"
22
29
  spec.add_development_dependency "rake"
23
30
  end
@@ -0,0 +1,153 @@
1
+ require "test_helper"
2
+
3
+ require "stretch/client"
4
+
5
+ describe Stretch::Client do
6
+ let(:instance) { described_class.new }
7
+ let(:connection) { MiniTest::Mock.new }
8
+
9
+ describe ".new" do
10
+ describe "scope defaults" do
11
+ it "index to nil" do
12
+ assert_nil instance.scope[:index]
13
+ end
14
+
15
+ it "cluster to false" do
16
+ refute instance.scope[:cluster]
17
+ end
18
+ end
19
+ end
20
+
21
+ it "can chain index" do
22
+ assert instance.index("foo").is_a?(Stretch::Client)
23
+ assert_equal "foo", instance.scope[:index]
24
+ end
25
+
26
+ it "can chain cluster" do
27
+ assert instance.cluster.is_a?(Stretch::Client)
28
+ assert instance.scope[:cluster]
29
+ end
30
+
31
+ describe "#health" do
32
+ it "requires either a cluster scope or an index scope" do
33
+ instance.stub :scope, { :cluster => false, :index => nil } do
34
+ assert_raises Stretch::InvalidScope do
35
+ instance.health
36
+ end
37
+ end
38
+ end
39
+
40
+ it "requests cluster health if the scope is cluster" do
41
+ instance.stub :connection, connection do
42
+ connection.expect :get, { "status" => "ok" }, ["/_cluster/health", {}]
43
+ instance.cluster.health
44
+
45
+ connection.verify
46
+ end
47
+ end
48
+
49
+ it "requests index health if the scope is an index" do
50
+ instance.stub :connection, connection do
51
+ connection.expect :get, { "status" => "ok" }, ["/foo/health", {}]
52
+ instance.index("foo").health
53
+
54
+ connection.verify
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#state" do
60
+ it "requires a cluster scope" do
61
+ instance.stub :scope, { :cluster => false } do
62
+ assert_raises Stretch::InvalidScope do
63
+ instance.state
64
+ end
65
+ end
66
+ end
67
+
68
+ it "can return the state of a cluster" do
69
+ instance.connection.stub :get, { "status" => "ok" } do
70
+ assert_equal "ok", instance.cluster.state["status"]
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "#settings" do
76
+ it "requires either a cluster scope or an index scope" do
77
+ instance.stub :scope, { :cluster => false, :index => nil } do
78
+ assert_raises Stretch::InvalidScope do
79
+ instance.settings
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "no options given" do
85
+ it "performs a get request for the settings" do
86
+ response = { "persistent" => { "foo" => 1 } }
87
+
88
+ instance.stub :connection, connection do
89
+ connection.expect :get, response, ["/_cluster/settings"]
90
+ assert_equal 1, instance.cluster.settings["persistent"]["foo"]
91
+
92
+ connection.verify
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "options given" do
98
+ it "performs a put request with options for the settings" do
99
+ params = { :index => { :refresh_interval => -1 } }
100
+ response = { "index" => {"refresh_interval" => -1} }
101
+
102
+ instance.stub :connection, connection do
103
+ connection.expect :put, response, ["/foo/settings", params]
104
+ assert_equal -1, instance.index("foo").settings(params)["index"]["refresh_interval"]
105
+
106
+ connection.verify
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "#open!" do
113
+ it "requires the index scope" do
114
+ instance.stub :scope, { :cluster => true, :index => nil } do
115
+ assert_raises Stretch::InvalidScope do
116
+ instance.open!
117
+ end
118
+ end
119
+ end
120
+
121
+ it "performs a post request to open the index" do
122
+ response = { "ok" => true, "acknowledged" => true }
123
+
124
+ instance.stub :connection, connection do
125
+ connection.expect :post, response, ["/foo/_open"]
126
+ assert_equal true, instance.index("foo").open!["ok"]
127
+
128
+ connection.verify
129
+ end
130
+ end
131
+ end
132
+
133
+ describe "#close!" do
134
+ it "requires the index scope" do
135
+ instance.stub :scope, { :cluster => true, :index => nil } do
136
+ assert_raises Stretch::InvalidScope do
137
+ instance.close!
138
+ end
139
+ end
140
+ end
141
+
142
+ it "performs a post request to close the index" do
143
+ response = { "ok" => true, "acknowledged" => true }
144
+
145
+ instance.stub :connection, connection do
146
+ connection.expect :post, response, ["/foo/_close"]
147
+ assert_equal true, instance.index("foo").close!["ok"]
148
+
149
+ connection.verify
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,42 @@
1
+ require "test_helper"
2
+
3
+ require "stretch/connection"
4
+
5
+ describe Stretch::Connection do
6
+ let(:instance) { described_class.new }
7
+ let(:response) do
8
+ Struct.new :response do
9
+ def body
10
+ MultiJson.dump({ "status" => "ok" })
11
+ end
12
+
13
+ def success?
14
+ true
15
+ end
16
+ end.new
17
+ end
18
+
19
+ it "accepts get requests" do
20
+ instance.connection.stub :get, response do
21
+ instance.get "/foo"
22
+ end
23
+ end
24
+
25
+ it "accepts post requests" do
26
+ instance.connection.stub :post, response do
27
+ instance.post "/foo"
28
+ end
29
+ end
30
+
31
+ it "accepts put requests" do
32
+ instance.connection.stub :put, response do
33
+ instance.put "/foo"
34
+ end
35
+ end
36
+
37
+ it "accepts delete requests" do
38
+ instance.connection.stub :delete, response do
39
+ instance.delete "/foo"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ require "test_helper"
2
+
3
+ require "stretch"
4
+
5
+ describe Stretch do
6
+ it "is a defined module name" do
7
+ assert defined?(Stretch)
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "minitest/spec"
5
+ require "minitest/autorun"
6
+
7
+ class MiniTest::Spec
8
+ def described_class
9
+ @described_class ||= self.class.ancestors.select { |c|
10
+ c.respond_to? :desc
11
+ }[-2].desc
12
+ end
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stretch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,40 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-12 00:00:00.000000000 Z
12
+ date: 2013-04-14 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.8.7
30
+ - !ruby/object:Gem::Dependency
31
+ name: multi_json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.7.2
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.7.2
14
46
  - !ruby/object:Gem::Dependency
15
47
  name: bundler
16
48
  requirement: !ruby/object:Gem::Requirement
@@ -18,7 +50,23 @@ dependencies:
18
50
  requirements:
19
51
  - - ~>
20
52
  - !ruby/object:Gem::Version
21
- version: '1.3'
53
+ version: '1.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '4.0'
22
70
  type: :development
23
71
  prerelease: false
24
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +74,23 @@ dependencies:
26
74
  requirements:
27
75
  - - ~>
28
76
  - !ruby/object:Gem::Version
29
- version: '1.3'
77
+ version: '4.0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: pry
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
30
94
  - !ruby/object:Gem::Dependency
31
95
  name: rake
32
96
  requirement: !ruby/object:Gem::Requirement
@@ -43,7 +107,7 @@ dependencies:
43
107
  - - ! '>='
44
108
  - !ruby/object:Gem::Version
45
109
  version: '0'
46
- description: Shh, it's a secret
110
+ description: An Elasticsearch client library
47
111
  email:
48
112
  - wfarr@github.com
49
113
  executables: []
@@ -51,14 +115,25 @@ extensions: []
51
115
  extra_rdoc_files: []
52
116
  files:
53
117
  - .gitignore
118
+ - .travis.yml
119
+ - CONTRIBUTING.md
54
120
  - Gemfile
55
121
  - LICENSE.txt
56
122
  - README.md
57
123
  - Rakefile
58
124
  - lib/stretch.rb
125
+ - lib/stretch/client.rb
126
+ - lib/stretch/connection.rb
127
+ - lib/stretch/uri_builder.rb
59
128
  - lib/stretch/version.rb
129
+ - script/bootstrap
130
+ - script/test
60
131
  - stretch.gemspec
61
- homepage: ''
132
+ - test/stretch/client_test.rb
133
+ - test/stretch/connection_test.rb
134
+ - test/stretch_test.rb
135
+ - test/test_helper.rb
136
+ homepage: https://github.com/wfarr/stretch
62
137
  licenses:
63
138
  - MIT
64
139
  post_install_message:
@@ -71,16 +146,27 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
146
  - - ! '>='
72
147
  - !ruby/object:Gem::Version
73
148
  version: '0'
149
+ segments:
150
+ - 0
151
+ hash: 3712832259908765
74
152
  required_rubygems_version: !ruby/object:Gem::Requirement
75
153
  none: false
76
154
  requirements:
77
155
  - - ! '>='
78
156
  - !ruby/object:Gem::Version
79
157
  version: '0'
158
+ segments:
159
+ - 0
160
+ hash: 3712832259908765
80
161
  requirements: []
81
162
  rubyforge_project:
82
163
  rubygems_version: 1.8.23
83
164
  signing_key:
84
165
  specification_version: 3
85
- summary: Still seriously a secret
86
- test_files: []
166
+ summary: It's not anywhere near complete at this time, but the code is pretty all
167
+ right allegedly.
168
+ test_files:
169
+ - test/stretch/client_test.rb
170
+ - test/stretch/connection_test.rb
171
+ - test/stretch_test.rb
172
+ - test/test_helper.rb