rubberband 0.0.2 → 0.0.4

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.
@@ -0,0 +1,101 @@
1
+ begin
2
+ require 'thrift'
3
+ rescue LoadError => error
4
+ raise "Please install the thrift gem (>= 0.5.0) to use the Thrift transport."
5
+ end
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "thrift"))
8
+ require 'rest'
9
+
10
+ module ElasticSearch
11
+ module Transport
12
+ class Thrift < Base
13
+
14
+ DEFAULTS = {
15
+ :timeout => 5,
16
+ :thrift_protocol => ::Thrift::BinaryProtocol,
17
+ :thrift_protocol_extra_params => [],
18
+ :thrift_transport => ::Thrift::Socket,
19
+ :thrift_transport_wrapper => ::Thrift::BufferedTransport,
20
+ :client_class => ElasticSearch::Thrift::Rest::Client
21
+ }.freeze
22
+
23
+ def initialize(server, options={})
24
+ super
25
+ @options = DEFAULTS.merge(@options)
26
+ end
27
+
28
+ def connect!
29
+ host, port = parse_server(@server)
30
+
31
+ @transport = @options[:thrift_transport].new(host, port.to_i, @options[:timeout])
32
+ @transport = @transport_wrapper.new(@transport) if @transport_wrapper
33
+ @transport.open
34
+
35
+ @client = @options[:client_class].new(@options[:thrift_protocol].new(@transport, *@options[:thrift_protocol_extra_params]))
36
+ rescue ::Thrift::TransportException, Errno::ECONNREFUSED
37
+ close
38
+ raise ConnectionFailed
39
+ end
40
+
41
+ def close
42
+ @transport.close rescue nil
43
+ end
44
+
45
+ private
46
+
47
+ def parse_server(server)
48
+ host, port = server.to_s.split(":")
49
+ raise ArgumentError, 'Servers must be in the form "host:port"' unless host and port
50
+ [host, port]
51
+ end
52
+
53
+ def stringify!(hash)
54
+ hash.keys.each do |k|
55
+ hash[k.to_s] = hash.delete(k).to_s
56
+ end
57
+ hash
58
+ end
59
+
60
+ def request(method, operation, params={}, body=nil, headers={})
61
+ begin
62
+ uri = generate_uri(operation)
63
+ #puts "request: #{@server} #{method} #{uri} #{params.inspect} #{body}"
64
+ request = ElasticSearch::Thrift::RestRequest.new
65
+ case method
66
+ when :get
67
+ request.method = ElasticSearch::Thrift::Method::GET
68
+ when :put
69
+ request.method = ElasticSearch::Thrift::Method::GET
70
+ when :post
71
+ request.method = ElasticSearch::Thrift::Method::POST
72
+ when :delete
73
+ request.method = ElasticSearch::Thrift::Method::DELETE
74
+ end
75
+
76
+ request.uri = uri
77
+ request.parameters = stringify!(params)
78
+ request.body = body
79
+ request.headers = stringify!(headers)
80
+ response = @client.execute(request)
81
+ handle_error(response) if response.status >= 500
82
+ response
83
+ rescue Exception => e
84
+ case e
85
+ when ::Thrift::TransportException
86
+ case e.type
87
+ when ::Thrift::TransportException::TIMED_OUT
88
+ raise TimeoutError
89
+ else
90
+ raise ConnectionFailed
91
+ end
92
+ #TODO Thrift::ApplicationException, Thrift::ProtocolException, IOError.. retryable or fatal?
93
+ else
94
+ raise e
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # Autogenerated by Thrift
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'elasticsearch_types'
8
+
9
+ module ElasticSearch
10
+ module Thrift
11
+ end
12
+ end
@@ -0,0 +1,124 @@
1
+ #
2
+ # Autogenerated by Thrift
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+
8
+ module ElasticSearch
9
+ module Thrift
10
+ module Method
11
+ GET = 0
12
+ PUT = 1
13
+ POST = 2
14
+ DELETE = 3
15
+ HEAD = 4
16
+ OPTIONS = 5
17
+ VALUE_MAP = {0 => "GET", 1 => "PUT", 2 => "POST", 3 => "DELETE", 4 => "HEAD", 5 => "OPTIONS"}
18
+ VALID_VALUES = Set.new([GET, PUT, POST, DELETE, HEAD, OPTIONS]).freeze
19
+ end
20
+
21
+ module Status
22
+ CONT = 100
23
+ SWITCHING_PROTOCOLS = 101
24
+ OK = 200
25
+ CREATED = 201
26
+ ACCEPTED = 202
27
+ NON_AUTHORITATIVE_INFORMATION = 203
28
+ NO_CONTENT = 204
29
+ RESET_CONTENT = 205
30
+ PARTIAL_CONTENT = 206
31
+ MULTI_STATUS = 207
32
+ MULTIPLE_CHOICES = 300
33
+ MOVED_PERMANENTLY = 301
34
+ FOUND = 302
35
+ SEE_OTHER = 303
36
+ NOT_MODIFIED = 304
37
+ USE_PROXY = 305
38
+ TEMPORARY_REDIRECT = 307
39
+ BAD_REQUEST = 400
40
+ UNAUTHORIZED = 401
41
+ PAYMENT_REQUIRED = 402
42
+ FORBIDDEN = 403
43
+ NOT_FOUND = 404
44
+ METHOD_NOT_ALLOWED = 405
45
+ NOT_ACCEPTABLE = 406
46
+ PROXY_AUTHENTICATION = 407
47
+ REQUEST_TIMEOUT = 408
48
+ CONFLICT = 409
49
+ GONE = 410
50
+ LENGTH_REQUIRED = 411
51
+ PRECONDITION_FAILED = 412
52
+ REQUEST_ENTITY_TOO_LARGE = 413
53
+ REQUEST_URI_TOO_LONG = 414
54
+ UNSUPPORTED_MEDIA_TYPE = 415
55
+ REQUESTED_RANGE_NOT_SATISFIED = 416
56
+ EXPECTATION_FAILED = 417
57
+ UNPROCESSABLE_ENTITY = 422
58
+ LOCKED = 423
59
+ FAILED_DEPENDENCY = 424
60
+ INTERNAL_SERVER_ERROR = 500
61
+ NOT_IMPLEMENTED = 501
62
+ BAD_GATEWAY = 502
63
+ SERVICE_UNAVAILABLE = 503
64
+ GATEWAY_TIMEOUT = 504
65
+ INSUFFICIENT_STORAGE = 506
66
+ VALUE_MAP = {100 => "CONT", 101 => "SWITCHING_PROTOCOLS", 200 => "OK", 201 => "CREATED", 202 => "ACCEPTED", 203 => "NON_AUTHORITATIVE_INFORMATION", 204 => "NO_CONTENT", 205 => "RESET_CONTENT", 206 => "PARTIAL_CONTENT", 207 => "MULTI_STATUS", 300 => "MULTIPLE_CHOICES", 301 => "MOVED_PERMANENTLY", 302 => "FOUND", 303 => "SEE_OTHER", 304 => "NOT_MODIFIED", 305 => "USE_PROXY", 307 => "TEMPORARY_REDIRECT", 400 => "BAD_REQUEST", 401 => "UNAUTHORIZED", 402 => "PAYMENT_REQUIRED", 403 => "FORBIDDEN", 404 => "NOT_FOUND", 405 => "METHOD_NOT_ALLOWED", 406 => "NOT_ACCEPTABLE", 407 => "PROXY_AUTHENTICATION", 408 => "REQUEST_TIMEOUT", 409 => "CONFLICT", 410 => "GONE", 411 => "LENGTH_REQUIRED", 412 => "PRECONDITION_FAILED", 413 => "REQUEST_ENTITY_TOO_LARGE", 414 => "REQUEST_URI_TOO_LONG", 415 => "UNSUPPORTED_MEDIA_TYPE", 416 => "REQUESTED_RANGE_NOT_SATISFIED", 417 => "EXPECTATION_FAILED", 422 => "UNPROCESSABLE_ENTITY", 423 => "LOCKED", 424 => "FAILED_DEPENDENCY", 500 => "INTERNAL_SERVER_ERROR", 501 => "NOT_IMPLEMENTED", 502 => "BAD_GATEWAY", 503 => "SERVICE_UNAVAILABLE", 504 => "GATEWAY_TIMEOUT", 506 => "INSUFFICIENT_STORAGE"}
67
+ VALID_VALUES = Set.new([CONT, SWITCHING_PROTOCOLS, OK, CREATED, ACCEPTED, NON_AUTHORITATIVE_INFORMATION, NO_CONTENT, RESET_CONTENT, PARTIAL_CONTENT, MULTI_STATUS, MULTIPLE_CHOICES, MOVED_PERMANENTLY, FOUND, SEE_OTHER, NOT_MODIFIED, USE_PROXY, TEMPORARY_REDIRECT, BAD_REQUEST, UNAUTHORIZED, PAYMENT_REQUIRED, FORBIDDEN, NOT_FOUND, METHOD_NOT_ALLOWED, NOT_ACCEPTABLE, PROXY_AUTHENTICATION, REQUEST_TIMEOUT, CONFLICT, GONE, LENGTH_REQUIRED, PRECONDITION_FAILED, REQUEST_ENTITY_TOO_LARGE, REQUEST_URI_TOO_LONG, UNSUPPORTED_MEDIA_TYPE, REQUESTED_RANGE_NOT_SATISFIED, EXPECTATION_FAILED, UNPROCESSABLE_ENTITY, LOCKED, FAILED_DEPENDENCY, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, INSUFFICIENT_STORAGE]).freeze
68
+ end
69
+
70
+ class RestRequest
71
+ include ::Thrift::Struct, ::Thrift::Struct_Union
72
+ METHOD = 1
73
+ URI = 2
74
+ PARAMETERS = 3
75
+ HEADERS = 4
76
+ BODY = 5
77
+
78
+ FIELDS = {
79
+ METHOD => {:type => ::Thrift::Types::I32, :name => 'method', :enum_class => ElasticSearch::Thrift::Method},
80
+ URI => {:type => ::Thrift::Types::STRING, :name => 'uri'},
81
+ PARAMETERS => {:type => ::Thrift::Types::MAP, :name => 'parameters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
82
+ HEADERS => {:type => ::Thrift::Types::MAP, :name => 'headers', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
83
+ BODY => {:type => ::Thrift::Types::STRING, :name => 'body', :binary => true, :optional => true}
84
+ }
85
+
86
+ def struct_fields; FIELDS; end
87
+
88
+ def validate
89
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field method is unset!') unless @method
90
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field uri is unset!') unless @uri
91
+ unless @method.nil? || ElasticSearch::Thrift::Method::VALID_VALUES.include?(@method)
92
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field method!')
93
+ end
94
+ end
95
+
96
+ ::Thrift::Struct.generate_accessors self
97
+ end
98
+
99
+ class RestResponse
100
+ include ::Thrift::Struct, ::Thrift::Struct_Union
101
+ STATUS = 1
102
+ HEADERS = 2
103
+ BODY = 3
104
+
105
+ FIELDS = {
106
+ STATUS => {:type => ::Thrift::Types::I32, :name => 'status', :enum_class => ElasticSearch::Thrift::Status},
107
+ HEADERS => {:type => ::Thrift::Types::MAP, :name => 'headers', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
108
+ BODY => {:type => ::Thrift::Types::STRING, :name => 'body', :binary => true, :optional => true}
109
+ }
110
+
111
+ def struct_fields; FIELDS; end
112
+
113
+ def validate
114
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field status is unset!') unless @status
115
+ unless @status.nil? || ElasticSearch::Thrift::Status::VALID_VALUES.include?(@status)
116
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field status!')
117
+ end
118
+ end
119
+
120
+ ::Thrift::Struct.generate_accessors self
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,83 @@
1
+ #
2
+ # Autogenerated by Thrift
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'elasticsearch_types'
9
+
10
+ module ElasticSearch
11
+ module Thrift
12
+ module Rest
13
+ class Client
14
+ include ::Thrift::Client
15
+
16
+ def execute(request)
17
+ send_execute(request)
18
+ return recv_execute()
19
+ end
20
+
21
+ def send_execute(request)
22
+ send_message('execute', Execute_args, :request => request)
23
+ end
24
+
25
+ def recv_execute()
26
+ result = receive_message(Execute_result)
27
+ return result.success unless result.success.nil?
28
+ raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'execute failed: unknown result')
29
+ end
30
+
31
+ end
32
+
33
+ class Processor
34
+ include ::Thrift::Processor
35
+
36
+ def process_execute(seqid, iprot, oprot)
37
+ args = read_args(iprot, Execute_args)
38
+ result = Execute_result.new()
39
+ result.success = @handler.execute(args.request)
40
+ write_result(result, oprot, 'execute', seqid)
41
+ end
42
+
43
+ end
44
+
45
+ # HELPER FUNCTIONS AND STRUCTURES
46
+
47
+ class Execute_args
48
+ include ::Thrift::Struct, ::Thrift::Struct_Union
49
+ REQUEST = 1
50
+
51
+ FIELDS = {
52
+ REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class => ElasticSearch::Thrift::RestRequest}
53
+ }
54
+
55
+ def struct_fields; FIELDS; end
56
+
57
+ def validate
58
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field request is unset!') unless @request
59
+ end
60
+
61
+ ::Thrift::Struct.generate_accessors self
62
+ end
63
+
64
+ class Execute_result
65
+ include ::Thrift::Struct, ::Thrift::Struct_Union
66
+ SUCCESS = 0
67
+
68
+ FIELDS = {
69
+ SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class => ElasticSearch::Thrift::RestResponse}
70
+ }
71
+
72
+ def struct_fields; FIELDS; end
73
+
74
+ def validate
75
+ end
76
+
77
+ ::Thrift::Struct.generate_accessors self
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1 @@
1
+ require 'elasticsearch'
@@ -0,0 +1,83 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rubberband}
8
+ s.version = "0.0.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["grantr"]
12
+ s.date = %q{2010-12-06}
13
+ s.description = %q{An ElasticSearch Client with ThriftClient-like failover handling.}
14
+ s.email = %q{grantr@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "TODO",
25
+ "VERSION",
26
+ "lib/elasticsearch.rb",
27
+ "lib/elasticsearch/client.rb",
28
+ "lib/elasticsearch/client/abstract_client.rb",
29
+ "lib/elasticsearch/client/admin_cluster.rb",
30
+ "lib/elasticsearch/client/admin_index.rb",
31
+ "lib/elasticsearch/client/auto_discovering_client.rb",
32
+ "lib/elasticsearch/client/default_scope.rb",
33
+ "lib/elasticsearch/client/hits.rb",
34
+ "lib/elasticsearch/client/index.rb",
35
+ "lib/elasticsearch/client/retrying_client.rb",
36
+ "lib/elasticsearch/encoding.rb",
37
+ "lib/elasticsearch/encoding/base.rb",
38
+ "lib/elasticsearch/encoding/json.rb",
39
+ "lib/elasticsearch/transport.rb",
40
+ "lib/elasticsearch/transport/base.rb",
41
+ "lib/elasticsearch/transport/base_protocol.rb",
42
+ "lib/elasticsearch/transport/http.rb",
43
+ "lib/elasticsearch/transport/thrift.rb",
44
+ "lib/elasticsearch/transport/thrift/elasticsearch_constants.rb",
45
+ "lib/elasticsearch/transport/thrift/elasticsearch_types.rb",
46
+ "lib/elasticsearch/transport/thrift/rest.rb",
47
+ "lib/rubberband.rb",
48
+ "rubberband.gemspec",
49
+ "test/elasticsearch_test.rb",
50
+ "test/hits_test.rb",
51
+ "test/test_helper.rb",
52
+ "vendor/elasticsearch/elasticsearch.thrift"
53
+ ]
54
+ s.homepage = %q{http://github.com/grantr/rubberband}
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.3.7}
57
+ s.summary = %q{An ElasticSearch client.}
58
+ s.test_files = [
59
+ "test/elasticsearch_test.rb",
60
+ "test/hits_test.rb",
61
+ "test/test_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
+ s.add_runtime_dependency(%q<patron>, [">= 0"])
70
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
71
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
72
+ else
73
+ s.add_dependency(%q<patron>, [">= 0"])
74
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
75
+ s.add_dependency(%q<shoulda>, [">= 0"])
76
+ end
77
+ else
78
+ s.add_dependency(%q<patron>, [">= 0"])
79
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
80
+ s.add_dependency(%q<shoulda>, [">= 0"])
81
+ end
82
+ end
83
+
@@ -2,6 +2,6 @@ require 'test_helper'
2
2
 
3
3
  class ElasticSearchTest < Test::Unit::TestCase
4
4
  should "probably rename this file and start testing for real" do
5
- flunk "hey buddy, you should probably rename this file and start testing for real"
5
+ #flunk "hey buddy, you should probably rename this file and start testing for real"
6
6
  end
7
7
  end
@@ -19,16 +19,83 @@ class HitsTest < Test::Unit::TestCase
19
19
  assert @hit.attributes.frozen?
20
20
  end
21
21
 
22
-
23
22
  end
24
23
 
25
24
  context "A Hits instance" do
26
25
  setup do
27
- @response1 = {"_source" => {"foo" => "bar"}, "_id" => "1"}
28
- @hit = ElasticSearch::Api::Hit.new(@response)
29
-
26
+ @response = {
27
+ "_shards"=>{"total"=>30, "successful"=>30, "failed"=>0},
28
+ "hits"=>{"total"=>2, "max_score"=>1.0, "hits"=>[
29
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"1", "_score"=>1.0, "_source"=>{"foo" => "bar"}},
30
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"2", "_score"=>1.0, "_source"=>{"foo" => "baz"}}
31
+ ]}}
32
+ @hits = ElasticSearch::Api::Hits.new(@response)
33
+ end
34
+
35
+ should "set response" do
36
+ assert_equal @response, @hits.response
37
+ end
38
+
39
+ should "set total_entries" do
40
+ assert_equal @response["hits"]["hits"].size, @hits.total_entries
41
+ end
42
+
43
+ should "instantiate hits in order" do
44
+ @response["hits"]["hits"].each_with_index do |hit, i|
45
+ assert_equal ElasticSearch::Api::Hit.new(hit), @hits.hits[i]
46
+ end
30
47
  end
31
48
 
32
- should "exist"
49
+ should "freeze hits" do
50
+ assert @hits.hits.all? { |h| h.frozen? }
51
+ end
52
+
53
+ should "freeze hits array when frozen" do
54
+ @hits.freeze
55
+ assert @hits.hits.frozen?
56
+ end
57
+
58
+ should "respond to to_a" do
59
+ assert_equal @hits.hits, @hits.to_a
60
+ end
61
+
62
+ should "respond to array methods" do
63
+ assert @hits.respond_to?(:collect)
64
+ assert_equal @response["hits"]["hits"].collect { |h| h["_id"] }, @hits.collect { |h| h.id }
65
+ end
66
+ end
67
+
68
+ context "a paginated hits instance" do
69
+ setup do
70
+ @response = {
71
+ "_shards"=>{"total"=>30, "successful"=>30, "failed"=>0},
72
+ "hits"=>{"total"=>6, "max_score"=>1.0, "hits"=>[
73
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"3", "_score"=>1.0, "_source"=>{"foo" => "bar"}},
74
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"4", "_score"=>1.0, "_source"=>{"foo" => "baz"}}
75
+ ]}}
76
+ @per_page = 2
77
+ @page = 2
78
+ @hits = ElasticSearch::Api::Hits.new(@response, {:page => @page, :per_page => @per_page})
79
+ end
80
+
81
+ should "respond to total_pages" do
82
+ assert_equal (@response["hits"]["total"] / @per_page.to_f).ceil, @hits.total_pages
83
+ end
84
+
85
+ should "respond to next_page" do
86
+ assert_equal @page + 1, @hits.next_page
87
+ end
88
+
89
+ should "respond to previous_page" do
90
+ assert_equal @page - 1, @hits.previous_page
91
+ end
92
+
93
+ should "respond to current_page" do
94
+ assert_equal @page, @hits.current_page
95
+ end
96
+
97
+ should "respond to per page" do
98
+ assert_equal @per_page, @hits.per_page
99
+ end
33
100
  end
34
101
  end