sonic-ruby 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 481516faf364a56439e535dfe4bcfbadb957b2c736a1f1db0a2731ff9e949c45
4
- data.tar.gz: df5508697fbc38eb549b1bc9c9c9b4eba6c4cc62e5a59519e0cc44fe2fa9fa92
3
+ metadata.gz: 11f88ebf448e0353b9a260f54f223b9013bf184079f350e6ec9fe23782d3b274
4
+ data.tar.gz: 4522c74a64130e54a6990355999575f9e557fa51a59ae9b847a162acd182a8c4
5
5
  SHA512:
6
- metadata.gz: 2a572c3d807069ef41574e60a9ee6df12d8b5bbc2ffd6893e97659c2b1c1ec741b3fbd04e4031b8cc9654415553f150ed45781417c80a3fc1f980b73574b0489
7
- data.tar.gz: 4dd866ce47e4f63e2a520ad9bd39fa99a5b3d8e678366c1276be95b2543e7685fc2f67876b118223e84b4ece4dbfb935617a5f38f5d8a22623007ad1b4924a53
6
+ metadata.gz: b7fde18e4818984c29d07354706a907e04664eca736fe17bbe5584212532520009a41162cd86a7807cc1f316dd707fc34f44e4294439f231b1c8fef38c134ac7
7
+ data.tar.gz: 378de35eb10db30414aa16dc0c746b44b748c94ac74790ced01729c3ed4330eba245ff17b1f815644a935401ebcc84eeebc1e6a62e1982a3ba45d972f449b3e2
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,97 @@
1
+ # sonic-ruby
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/sonic-ruby.svg)](https://badge.fury.io/rb/sonic-ruby)
4
+ [![Build Status](https://travis-ci.com/atipugin/sonic-ruby.svg?branch=master)](https://travis-ci.com/atipugin/sonic-ruby)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/dcbb9919a64c96fb629c/maintainability)](https://codeclimate.com/github/atipugin/sonic-ruby/maintainability)
6
+
7
+ A Ruby client for [Sonic search backend](https://github.com/valeriansaliou/sonic).
8
+
9
+ ## Installation
10
+
11
+ Add following line to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'sonic-ruby'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```shell
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it system-wide:
24
+
25
+ ```shell
26
+ $ gem install sonic-ruby
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ Start with creating new client:
32
+
33
+ ```ruby
34
+ client = Sonic::Client.new('localhost', 1491, 'SecretPassword')
35
+ ```
36
+
37
+ Now you can use `#channel` method in order to connect to specific channels:
38
+
39
+ ```ruby
40
+ control = client.channel(:control)
41
+ ingest = client.channel(:ingest)
42
+ search = client.channel(:search)
43
+ ```
44
+
45
+ [Learn more about Sonic Channels](https://github.com/valeriansaliou/sonic/blob/master/PROTOCOL.md).
46
+
47
+ ## Indexing
48
+
49
+ ```ruby
50
+ # Init `ingest` channel
51
+ ingest = client.channel(:ingest)
52
+
53
+ # Add data to index
54
+ ingest.push('users', 'all', 1, 'Alexander Tipugin')
55
+ # => true
56
+
57
+ # Remove data from index
58
+ ingest.pop('users', 'all', 1, 'Alexander Tipugin')
59
+ # => 2
60
+
61
+ # Count collection/bucket/object items
62
+ ingest.count('users', 'all', 1)
63
+ # => 1
64
+
65
+ # Flush entire collection
66
+ ingest.flushc('users')
67
+ # => 1
68
+
69
+ # Flush entire bucket inside collection
70
+ ingest.flushb('users', 'all')
71
+ # => 1
72
+
73
+ # Flush specific object inside bucket
74
+ ingest.flusho('users', 'all', 1)
75
+ # => 2
76
+ ```
77
+
78
+ ## Searching
79
+
80
+ ```ruby
81
+ # Init `search` channel
82
+ search = client.channel(:search)
83
+
84
+ # Find indexed object by term
85
+ search.query('users', 'all', 'tipugin')
86
+ # => 1
87
+
88
+ # Auto-complete word
89
+ search.suggest('users', 'all', 'alex')
90
+ # => alexander
91
+ ```
92
+
93
+ ## TODO
94
+
95
+ - [ ] Take into account maximum buffer size.
96
+ - [ ] Consider using connection pool.
97
+ - [x] Return more meaningful responses from commands (i.e. bool `true` instead of string `OK`, int `1` instead of string `RESULT 1` etc).
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'bundler/setup'
3
+ require 'rubocop/rake_task'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RuboCop::RakeTask.new(:rubocop) do |task|
7
+ task.patterns = %w[lib/**/*.rb]
8
+ end
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task default: :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup'
3
+ require 'pry'
4
+
5
+ require File.expand_path('../../lib/sonic', __FILE__)
6
+
7
+ Pry.start
@@ -0,0 +1 @@
1
+ require 'sonic'
@@ -0,0 +1,7 @@
1
+ require 'socket'
2
+
3
+ require 'sonic/version'
4
+ require 'sonic/client'
5
+ require 'sonic/channels'
6
+ require 'sonic/connection'
7
+ require 'sonic/errors'
@@ -0,0 +1,4 @@
1
+ require 'sonic/channels/base'
2
+ require 'sonic/channels/control'
3
+ require 'sonic/channels/ingest'
4
+ require 'sonic/channels/search'
@@ -0,0 +1,48 @@
1
+ module Sonic
2
+ module Channels
3
+ class Base
4
+ attr_reader :connection
5
+
6
+ def initialize(connection)
7
+ @connection = connection
8
+ end
9
+
10
+ def ping
11
+ execute('PING')
12
+ end
13
+
14
+ def help(manual)
15
+ execute('HELP', manual)
16
+ end
17
+
18
+ def quit
19
+ execute('QUIT')
20
+ connection.disconnect
21
+ end
22
+
23
+ private
24
+
25
+ def execute(*args)
26
+ connection.write(*args.join(' '))
27
+ yield if block_given?
28
+ type_cast_response(connection.read)
29
+ end
30
+
31
+ def quote(value)
32
+ "\"#{value}\""
33
+ end
34
+
35
+ def type_cast_response(value)
36
+ if value == 'OK'
37
+ true
38
+ elsif value.start_with?('RESULT ')
39
+ value.split(' ').last.to_i
40
+ elsif value.start_with?('EVENT ')
41
+ value.split(' ')[3..-1].join(' ')
42
+ else
43
+ value
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ module Sonic
2
+ module Channels
3
+ class Control < Base
4
+ def trigger(action)
5
+ execute('TRIGGER', action)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ module Sonic
2
+ module Channels
3
+ class Ingest < Base
4
+ def push(collection, bucket, object, text, lang = nil)
5
+ arr = [collection, bucket, object, quote(text)]
6
+ arr << "LANG(#{lang})" if lang
7
+
8
+ execute('PUSH', *arr)
9
+ end
10
+
11
+ def pop(collection, bucket, object, text)
12
+ execute('POP', collection, bucket, object, quote(text))
13
+ end
14
+
15
+ def count(collection, bucket = nil, object = nil)
16
+ execute('COUNT', *[collection, bucket, object].compact)
17
+ end
18
+
19
+ def flushc(collection)
20
+ execute('FLUSHC', collection)
21
+ end
22
+
23
+ def flushb(collection, bucket)
24
+ execute('FLUSHB', collection, bucket)
25
+ end
26
+
27
+ def flusho(collection, bucket, object)
28
+ execute('FLUSHO', collection, bucket, object)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ module Sonic
2
+ module Channels
3
+ class Search < Base
4
+ def query(collection, bucket, terms, limit = nil, offset = nil, lang = nil) # rubocop:disable Metrics/ParameterLists, Metrics/LineLength
5
+ arr = [collection, bucket, quote(terms)]
6
+ arr << "LIMIT(#{limit})" if limit
7
+ arr << "OFFSET(#{offset})" if offset
8
+ arr << "LANG(#{lang})" if lang
9
+
10
+ execute('QUERY', *arr) do
11
+ connection.read # ...
12
+ end
13
+ end
14
+
15
+ def suggest(collection, bucket, word, limit = nil)
16
+ arr = [collection, bucket, quote(word)]
17
+ arr << "LIMIT(#{limit})" if limit
18
+
19
+ execute('SUGGEST', *arr) do
20
+ connection.read # ...
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ module Sonic
2
+ class Client
3
+ def initialize(host, port, password = nil)
4
+ @host = host
5
+ @port = port
6
+ @password = password
7
+ end
8
+
9
+ def channel(type)
10
+ channel_class(type).new(Connection.connect(@host, @port, type, @password))
11
+ end
12
+
13
+ private
14
+
15
+ def channel_class(type)
16
+ case type.to_sym
17
+ when :control then Channels::Control
18
+ when :ingest then Channels::Ingest
19
+ when :search then Channels::Search
20
+ else raise ArgumentError, "`#{type}` channel type is not supported"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ module Sonic
2
+ class Connection
3
+ def self.connect(*args)
4
+ connection = new(*args)
5
+ connection if connection.connect
6
+ end
7
+
8
+ def initialize(host, port, channel_type, password = nil)
9
+ @host = host
10
+ @port = port
11
+ @channel_type = channel_type
12
+ @password = password
13
+ end
14
+
15
+ def connect
16
+ read # ...
17
+ write(['START', @channel_type, @password].compact.join(' '))
18
+ read.start_with?('STARTED ')
19
+ end
20
+
21
+ def disconnect
22
+ socket.close
23
+ end
24
+
25
+ def read
26
+ data = socket.gets.chomp
27
+ raise ServerError, data if data.start_with?('ERR ')
28
+
29
+ data
30
+ end
31
+
32
+ def write(data)
33
+ socket.puts(data)
34
+ end
35
+
36
+ private
37
+
38
+ def socket
39
+ @socket ||= TCPSocket.open(@host, @port)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,4 @@
1
+ module Sonic
2
+ class Error < StandardError; end
3
+ class ServerError < Error; end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Sonic
2
+ VERSION = '0.2.2'.freeze
3
+ end
@@ -0,0 +1,19 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'sonic/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'sonic-ruby'
8
+ spec.version = Sonic::VERSION
9
+ spec.summary = 'Ruby client for Sonic'
10
+ spec.authors = ['Alexander Tipugin']
11
+ spec.files = `git ls-files -z`.split("\x0").reject { |f|
12
+ f.match(%r{^(test|spec|features)/})
13
+ } - ['.rubocop.yml', '.travis.yml', 'Gemfile.lock', '.gitignore', '.rspec']
14
+
15
+ spec.add_development_dependency 'pry'
16
+ spec.add_development_dependency 'rake'
17
+ spec.add_development_dependency 'rspec'
18
+ spec.add_development_dependency 'rubocop', '~> 0.66.0'
19
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sonic-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Tipugin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-01 00:00:00.000000000 Z
11
+ date: 2019-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -71,7 +71,23 @@ email:
71
71
  executables: []
72
72
  extensions: []
73
73
  extra_rdoc_files: []
74
- files: []
74
+ files:
75
+ - Gemfile
76
+ - README.md
77
+ - Rakefile
78
+ - bin/console
79
+ - lib/sonic-ruby.rb
80
+ - lib/sonic.rb
81
+ - lib/sonic/channels.rb
82
+ - lib/sonic/channels/base.rb
83
+ - lib/sonic/channels/control.rb
84
+ - lib/sonic/channels/ingest.rb
85
+ - lib/sonic/channels/search.rb
86
+ - lib/sonic/client.rb
87
+ - lib/sonic/connection.rb
88
+ - lib/sonic/errors.rb
89
+ - lib/sonic/version.rb
90
+ - sonic-ruby.gemspec
75
91
  homepage:
76
92
  licenses: []
77
93
  metadata: {}