expedition 0.1.0
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +17 -0
- data/.pryrc +13 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/.yardopts +3 -0
- data/Gemfile +4 -0
- data/Guardfile +15 -0
- data/MIT-LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +6 -0
- data/bin/expedition +5 -0
- data/expedition.gemspec +37 -0
- data/lib/expedition/client.rb +68 -0
- data/lib/expedition/response.rb +56 -0
- data/lib/expedition/status.rb +58 -0
- data/lib/expedition/version.rb +3 -0
- data/lib/expedition.rb +33 -0
- data/spec/expedition/client_spec.rb +64 -0
- data/spec/expedition/response_spec.rb +314 -0
- data/spec/expedition_spec.rb +35 -0
- data/spec/spec_helper.rb +21 -0
- metadata +284 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 141d6721450724842c369dc719dc7c730bf9ca33
|
4
|
+
data.tar.gz: fe74ec4f70c28284ce8368ba260eccafebd6a307
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5be107f3cf7a0c8a449c3022e5d1fc9f1b862384a92db439e9d6c4125f49451714b4771dda11edd7cee6df4f803b16ee9276c3ea79251a92adfce5ae72aeb269
|
7
|
+
data.tar.gz: 3064b19068add7e17547c07b610655446e308a8e1fd9ee94759c1f5e420986f645ce0260e587c81cb5f6d4be2e8517ab779ec32940b505a4044e1082a90dbd6e
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
data/.pryrc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'expedition'
|
3
|
+
|
4
|
+
def reload!
|
5
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
6
|
+
Dir["#{File.dirname(__FILE__)}/lib/**/*.rb"].sort.each { |f| load f }
|
7
|
+
ensure
|
8
|
+
$VERBOSE = old_verbose
|
9
|
+
end
|
10
|
+
|
11
|
+
def client(host = 'localhost', port = 4028)
|
12
|
+
Expedition.new(host, port)
|
13
|
+
end
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
guard 'bundler' do
|
2
|
+
watch('Gemfile')
|
3
|
+
watch(%r{\w+\.gemspec})
|
4
|
+
end
|
5
|
+
|
6
|
+
guard 'rspec', cmd: 'bundle exec rspec', all_on_start: true do
|
7
|
+
watch(%r{^spec/.+_spec\.rb$})
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
9
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
10
|
+
watch(%r{^lib/config/locales}) { 'spec/launchkey/errors' }
|
11
|
+
end
|
12
|
+
|
13
|
+
guard 'yard' do
|
14
|
+
watch(%r{lib/.+\.rb})
|
15
|
+
end
|
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Gabe Evans
|
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,45 @@
|
|
1
|
+
# Expedition
|
2
|
+
|
3
|
+
Expedition is a gem for interacting with cgminer and cgminer-compatible APIs.
|
4
|
+
The goal of this project is to offer Rubyists easier integration with the
|
5
|
+
[cgminer API](https://github.com/ckolivas/cgminer/blob/master/API-README) “the
|
6
|
+
Ruby way.”
|
7
|
+
|
8
|
+
**tl;dr** This gem lets you interact with cgminer’s API the way a Ruby hipster
|
9
|
+
would want to.
|
10
|
+
|
11
|
+
Now for some fancy badges:
|
12
|
+
|
13
|
+
[](http://badge.fury.io/rb/expedition)
|
14
|
+
[](https://gemnasium.com/gevans/expedition)
|
15
|
+
[](https://travis-ci.org/gevans/expedition)
|
16
|
+
[](https://codeclimate.com/github/gevans/expedition)
|
17
|
+
[](https://coveralls.io/r/gevans/expedition?branch=master)
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'expedition'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
$ gem install expedition
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
TODO: Write usage instructions here
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
1. Fork it (http://github.com/gevans/expedition/fork)
|
42
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
43
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
44
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
45
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/expedition
ADDED
data/expedition.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'expedition/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'expedition'
|
8
|
+
spec.version = Expedition::VERSION
|
9
|
+
spec.authors = ['Gabe Evans']
|
10
|
+
spec.email = ['gabe@ga.be']
|
11
|
+
spec.summary = %q{Expedition is an implementation of the cgminer client protocol. It allows you to write programs that interact with cgminer and cgminer-compatible software.}
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = 'https://github.com/gevans/expedition'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = %w(lib)
|
20
|
+
|
21
|
+
spec.add_dependency 'multi_json', '~> 1.3'
|
22
|
+
spec.add_dependency 'activesupport', '~> 4.0'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
25
|
+
spec.add_development_dependency 'coveralls'
|
26
|
+
spec.add_development_dependency 'guard'
|
27
|
+
spec.add_development_dependency 'guard-bundler'
|
28
|
+
spec.add_development_dependency 'guard-rspec'
|
29
|
+
spec.add_development_dependency 'guard-yard'
|
30
|
+
spec.add_development_dependency 'pry'
|
31
|
+
spec.add_development_dependency 'rake'
|
32
|
+
spec.add_development_dependency 'rb-fsevent'
|
33
|
+
spec.add_development_dependency 'rb-inotify'
|
34
|
+
spec.add_development_dependency 'rspec'
|
35
|
+
spec.add_development_dependency 'terminal-notifier-guard'
|
36
|
+
spec.add_development_dependency 'yard'
|
37
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
require 'expedition/response'
|
5
|
+
|
6
|
+
module Expedition
|
7
|
+
class Client
|
8
|
+
|
9
|
+
##
|
10
|
+
# @return [String]
|
11
|
+
# The host this client will execute commands on.
|
12
|
+
attr_accessor :host
|
13
|
+
|
14
|
+
##
|
15
|
+
# @return [Integer]
|
16
|
+
# The host port this client will connect to.
|
17
|
+
attr_accessor :port
|
18
|
+
|
19
|
+
##
|
20
|
+
# Initializes a new `Client` for executing commands.
|
21
|
+
#
|
22
|
+
# @param [String] host
|
23
|
+
# The host to connect to.
|
24
|
+
#
|
25
|
+
# @param [Integer] port
|
26
|
+
# The port to connect to.
|
27
|
+
def initialize(host = 'localhost', port = 4028)
|
28
|
+
@host = host
|
29
|
+
@port = port
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Sends the supplied `command` with optionally supplied `parameters` to the
|
34
|
+
# service and returns the result, if any.
|
35
|
+
#
|
36
|
+
# **Note:** Since `Object#send` is overridden, use `Object#__send__` to call
|
37
|
+
# an actual method.
|
38
|
+
#
|
39
|
+
# @param [Symbol, String] command
|
40
|
+
# The command to send to the service.
|
41
|
+
#
|
42
|
+
# @param [Array] parameters
|
43
|
+
# Optional parameters to send to the service.
|
44
|
+
#
|
45
|
+
# @return [Response]
|
46
|
+
# The service's response.
|
47
|
+
def send(command, *parameters)
|
48
|
+
socket = TCPSocket.new(host, port)
|
49
|
+
socket.puts command_json(command, *parameters)
|
50
|
+
|
51
|
+
parse(socket.gets)
|
52
|
+
ensure
|
53
|
+
socket.close if socket.respond_to?(:close)
|
54
|
+
end
|
55
|
+
|
56
|
+
alias method_missing send
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def parse(response)
|
61
|
+
Response.parse(MultiJson.load(response.chomp("\x0")))
|
62
|
+
end
|
63
|
+
|
64
|
+
def command_json(command, *parameters)
|
65
|
+
MultiJson.dump(command: command, parameter: parameters.join(','))
|
66
|
+
end
|
67
|
+
end # Client
|
68
|
+
end # Expedition
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'expedition/status'
|
2
|
+
|
3
|
+
module Expedition
|
4
|
+
class Response
|
5
|
+
|
6
|
+
attr_reader :body
|
7
|
+
|
8
|
+
attr_reader :raw
|
9
|
+
|
10
|
+
attr_reader :status
|
11
|
+
|
12
|
+
def self.parse(raw)
|
13
|
+
new(normalize(raw), raw)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(normalized, raw)
|
17
|
+
@body = normalized
|
18
|
+
@raw = raw
|
19
|
+
@status = Status.new(normalized[:status])
|
20
|
+
end
|
21
|
+
|
22
|
+
delegate :success?, :informational?, :warning?, :error?, :fatal?,
|
23
|
+
:executed_at, to: :status
|
24
|
+
|
25
|
+
delegate :[], :to_hash, to: :body
|
26
|
+
|
27
|
+
def respond_to_missing?(method_name, include_private = false)
|
28
|
+
body.has_key?(method_name) || super
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(method_name, *arguments, &block)
|
32
|
+
if respond_to_missing?(method_name)
|
33
|
+
body[method_name]
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def self.normalize(value)
|
42
|
+
case value
|
43
|
+
when Hash
|
44
|
+
Hash[value.collect { |k, v| [normalize_key(k), normalize(v)] }]
|
45
|
+
when Array
|
46
|
+
value.collect { |v| normalize(v) }
|
47
|
+
else
|
48
|
+
value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.normalize_key(key)
|
53
|
+
key.gsub(/(\w)%/, '\\1_percent').gsub('%', 'percent').gsub(/\s/, '_').downcase.to_sym
|
54
|
+
end
|
55
|
+
end # Response
|
56
|
+
end # Expedition
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Expedition
|
2
|
+
class Status
|
3
|
+
|
4
|
+
SEVERITIES = {
|
5
|
+
'S' => :success,
|
6
|
+
'I' => :info,
|
7
|
+
'W' => :warning,
|
8
|
+
'E' => :error,
|
9
|
+
'F' => :fatal
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
OK_SEVERITIES = %i(success info warning).freeze
|
13
|
+
|
14
|
+
attr_reader :severity
|
15
|
+
|
16
|
+
attr_reader :code
|
17
|
+
|
18
|
+
attr_reader :message
|
19
|
+
|
20
|
+
attr_reader :description
|
21
|
+
|
22
|
+
attr_reader :executed_at
|
23
|
+
|
24
|
+
def initialize(body)
|
25
|
+
status = body.try(:first) || {}
|
26
|
+
|
27
|
+
@severity = SEVERITIES[status[:status]]
|
28
|
+
@code = status[:code]
|
29
|
+
@message = status[:msg]
|
30
|
+
@description = status[:description]
|
31
|
+
@executed_at = Time.at(status[:when]) rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def success?
|
35
|
+
severity == :success
|
36
|
+
end
|
37
|
+
|
38
|
+
def info?
|
39
|
+
severity == :info
|
40
|
+
end
|
41
|
+
|
42
|
+
def warning?
|
43
|
+
severity == :warning
|
44
|
+
end
|
45
|
+
|
46
|
+
def error?
|
47
|
+
severity == :error
|
48
|
+
end
|
49
|
+
|
50
|
+
def fatal?
|
51
|
+
severity == :fatal
|
52
|
+
end
|
53
|
+
|
54
|
+
def ok?
|
55
|
+
OK_SEVERITIES.include?(severity)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end # Expedition
|
data/lib/expedition.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
|
4
|
+
require 'expedition/client'
|
5
|
+
require 'expedition/version'
|
6
|
+
|
7
|
+
module Expedition
|
8
|
+
|
9
|
+
##
|
10
|
+
# Initializes a new {Expedition::Client}.
|
11
|
+
#
|
12
|
+
# @param [String] host
|
13
|
+
# The host to connect to.
|
14
|
+
#
|
15
|
+
# @param [Integer] port
|
16
|
+
# The port to connect to.
|
17
|
+
#
|
18
|
+
# @return [Client]
|
19
|
+
# A client for accessing the API of a cgminer-compatible service.
|
20
|
+
def self.new(host = 'localhost', port = 4028)
|
21
|
+
Client.new(host, port)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Returns the default client for connection to `localhost` on port `4028`.
|
26
|
+
# Used for simple scripts that access the `Expedition` constant directly.
|
27
|
+
#
|
28
|
+
# @return [Client]
|
29
|
+
# The default client.
|
30
|
+
def self.client
|
31
|
+
@client ||= new
|
32
|
+
end
|
33
|
+
end # Expedition
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Expedition::Client do
|
4
|
+
|
5
|
+
describe '#initialize' do
|
6
|
+
|
7
|
+
subject(:client) do
|
8
|
+
described_class.new('example.com', 1234)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'by default' do
|
12
|
+
|
13
|
+
subject(:client) do
|
14
|
+
described_class.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'sets host to "localhost"' do
|
18
|
+
expect(client.host).to eq('localhost')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'sets port to 4028' do
|
22
|
+
expect(client.port).to eq(4028)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'initializes with supplied host and port' do
|
27
|
+
expect(client.host).to eq('example.com')
|
28
|
+
expect(client.port).to eq(1234)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
%i(send method_missing).each do |method_name|
|
33
|
+
|
34
|
+
describe "##{method_name}" do
|
35
|
+
|
36
|
+
subject(:client) do
|
37
|
+
described_class.new
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:socket) do
|
41
|
+
double(TCPSocket)
|
42
|
+
end
|
43
|
+
|
44
|
+
before do
|
45
|
+
allow(TCPSocket).to receive(:new).with(client.host, client.port).and_return(socket)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'sends supplied command and parameters to configured host and port' do
|
49
|
+
expect(socket).to receive(:puts).with('{"command":"foo","parameter":"bar,baz"}')
|
50
|
+
expect(socket).to receive(:gets).and_return(%/{}\x0/)
|
51
|
+
client.__send__(method_name, 'foo', 'bar', 'baz')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns Expedition::Response with parsed body' do
|
55
|
+
expect(socket).to receive(:puts).with('{"command":"foo","parameter":"bar,baz"}')
|
56
|
+
expect(socket).to receive(:gets).and_return(%/{"what a":["body"]}\x0/)
|
57
|
+
result = client.__send__(method_name, 'foo', 'bar', 'baz')
|
58
|
+
expect(result.body).to eq(
|
59
|
+
what_a: ['body']
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,314 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Expedition::Response do
|
4
|
+
|
5
|
+
let(:original_data) do
|
6
|
+
{
|
7
|
+
'STATUS' => [
|
8
|
+
{
|
9
|
+
'STATUS' => 'S',
|
10
|
+
'When' => 1394855182,
|
11
|
+
'Code' => 17,
|
12
|
+
'Msg' => 'GPU0',
|
13
|
+
'Description' => 'sgminer 4.1.0'
|
14
|
+
}
|
15
|
+
],
|
16
|
+
'GPU' => [
|
17
|
+
{
|
18
|
+
'GPU' => 0,
|
19
|
+
'Enabled' => 'Y',
|
20
|
+
'Status' => 'Alive',
|
21
|
+
'Temperature' => 72.0,
|
22
|
+
'Fan Speed' => -1,
|
23
|
+
'Fan Percent' => 100,
|
24
|
+
'GPU Clock' => 947,
|
25
|
+
'Memory Clock' => 1500,
|
26
|
+
'GPU Voltage' => 0.0,
|
27
|
+
'GPU Activity' => 100,
|
28
|
+
'Powertune' => 30,
|
29
|
+
'MHS av' => 0.9245,
|
30
|
+
'MHS 5s' => 0.9228,
|
31
|
+
'KHS av' => 924,
|
32
|
+
'KHS 5s' => 923,
|
33
|
+
'Accepted' => 1627,
|
34
|
+
'Rejected' => 7,
|
35
|
+
'Hardware Errors' => 3359,
|
36
|
+
'Utility' => 0.5465,
|
37
|
+
'Intensity' => '20',
|
38
|
+
'Last Share Pool' => 0,
|
39
|
+
'Last Share Time' => 1394735379,
|
40
|
+
'Total MH' => 165125.5542,
|
41
|
+
'Diff1 Work' => 836803,
|
42
|
+
'Difficulty Accepted' => 833024.0,
|
43
|
+
'Difficulty Rejected' => 3584.0,
|
44
|
+
'Last Share Difficulty' => 512.0,
|
45
|
+
'Last Valid Work' => 1394735379,
|
46
|
+
'Device Hardware%' => 0.3998,
|
47
|
+
'Device Rejected%' => 0.4283,
|
48
|
+
'Device Elapsed' => 178612
|
49
|
+
}
|
50
|
+
],
|
51
|
+
'id' => 1
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:normalized_data) do
|
56
|
+
{
|
57
|
+
status: [
|
58
|
+
{
|
59
|
+
status: 'S',
|
60
|
+
when: 1394855182,
|
61
|
+
code: 17,
|
62
|
+
msg: 'GPU0',
|
63
|
+
description: 'sgminer 4.1.0'
|
64
|
+
}
|
65
|
+
],
|
66
|
+
gpu: [
|
67
|
+
{
|
68
|
+
gpu: 0,
|
69
|
+
enabled: 'Y',
|
70
|
+
status: 'Alive',
|
71
|
+
temperature: 72.0,
|
72
|
+
fan_speed: -1,
|
73
|
+
fan_percent: 100,
|
74
|
+
gpu_clock: 947,
|
75
|
+
memory_clock: 1500,
|
76
|
+
gpu_voltage: 0.0,
|
77
|
+
gpu_activity: 100,
|
78
|
+
powertune: 30,
|
79
|
+
mhs_av: 0.9245,
|
80
|
+
mhs_5s: 0.9228,
|
81
|
+
khs_av: 924,
|
82
|
+
khs_5s: 923,
|
83
|
+
accepted: 1627,
|
84
|
+
rejected: 7,
|
85
|
+
hardware_errors: 3359,
|
86
|
+
utility: 0.5465,
|
87
|
+
intensity: '20',
|
88
|
+
last_share_pool: 0,
|
89
|
+
last_share_time: 1394735379,
|
90
|
+
total_mh: 165125.5542,
|
91
|
+
diff1_work: 836803,
|
92
|
+
difficulty_accepted: 833024.0,
|
93
|
+
difficulty_rejected: 3584.0,
|
94
|
+
last_share_difficulty: 512.0,
|
95
|
+
last_valid_work: 1394735379,
|
96
|
+
device_hardware_percent: 0.3998,
|
97
|
+
device_rejected_percent: 0.4283,
|
98
|
+
device_elapsed: 178612
|
99
|
+
}
|
100
|
+
],
|
101
|
+
id: 1
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:response) do
|
106
|
+
described_class.parse(original_data)
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '.parse' do
|
110
|
+
|
111
|
+
subject { response }
|
112
|
+
|
113
|
+
it 'returns Expedition::Response' do
|
114
|
+
expect(response).to be_an(Expedition::Response)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'initializes with normalized and original data' do
|
118
|
+
expect(Expedition::Response).to receive(:new).with(normalized_data, original_data)
|
119
|
+
response
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'retains original hash' do
|
123
|
+
expect(response.raw).to eq(original_data)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#status' do
|
128
|
+
|
129
|
+
subject(:status) do
|
130
|
+
response.status
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'returns Expedition::Status' do
|
134
|
+
expect(status).to be_an(Expedition::Status)
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'when success' do
|
138
|
+
|
139
|
+
before do
|
140
|
+
original_data['STATUS'].first['STATUS'] = 'S'
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'is success' do
|
144
|
+
expect(status).to be_success
|
145
|
+
|
146
|
+
expect(status).not_to be_info
|
147
|
+
expect(status).not_to be_warning
|
148
|
+
expect(status).not_to be_info
|
149
|
+
expect(status).not_to be_info
|
150
|
+
expect(status).not_to be_info
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'is okay' do
|
154
|
+
expect(status).to be_ok
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when info' do
|
159
|
+
|
160
|
+
before do
|
161
|
+
original_data['STATUS'].first['STATUS'] = 'I'
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'is info' do
|
165
|
+
expect(status).to be_info
|
166
|
+
|
167
|
+
expect(status).not_to be_success
|
168
|
+
expect(status).not_to be_warning
|
169
|
+
expect(status).not_to be_error
|
170
|
+
expect(status).not_to be_fatal
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'is okay' do
|
174
|
+
expect(status).to be_ok
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'when warning' do
|
179
|
+
|
180
|
+
before do
|
181
|
+
original_data['STATUS'].first['STATUS'] = 'W'
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'is warning' do
|
185
|
+
expect(status).to be_warning
|
186
|
+
|
187
|
+
expect(status).not_to be_success
|
188
|
+
expect(status).not_to be_info
|
189
|
+
expect(status).not_to be_error
|
190
|
+
expect(status).not_to be_fatal
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'is okay' do
|
194
|
+
expect(status).to be_ok
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'when error' do
|
199
|
+
|
200
|
+
before do
|
201
|
+
original_data['STATUS'].first['STATUS'] = 'E'
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'is error' do
|
205
|
+
expect(status).to be_error
|
206
|
+
|
207
|
+
expect(status).not_to be_success
|
208
|
+
expect(status).not_to be_info
|
209
|
+
expect(status).not_to be_warning
|
210
|
+
expect(status).not_to be_fatal
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'is not okay' do
|
214
|
+
expect(status).not_to be_ok
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'when fatal' do
|
219
|
+
|
220
|
+
before do
|
221
|
+
original_data['STATUS'].first['STATUS'] = 'F'
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'is fatal' do
|
225
|
+
expect(status).to be_fatal
|
226
|
+
|
227
|
+
expect(status).not_to be_success
|
228
|
+
expect(status).not_to be_info
|
229
|
+
expect(status).not_to be_warning
|
230
|
+
expect(status).not_to be_error
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'is not okay' do
|
234
|
+
expect(status).not_to be_ok
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
%i(success? informational? warning? error? fatal? executed_at).each do |method_name|
|
240
|
+
|
241
|
+
describe "##{method_name}" do
|
242
|
+
|
243
|
+
it 'delegates to #status' do
|
244
|
+
expect(response.status).to receive(method_name)
|
245
|
+
response.send(method_name)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
%i([] to_hash).each do |method_name|
|
251
|
+
|
252
|
+
describe "##{method_name}" do
|
253
|
+
|
254
|
+
it 'delegates to #body' do
|
255
|
+
expect(response.body).to receive(method_name)
|
256
|
+
response.send(method_name)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe '#respond_to_missing?' do
|
262
|
+
|
263
|
+
let(:response) do
|
264
|
+
described_class.new(body, {})
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'when #body has key' do
|
268
|
+
|
269
|
+
let(:body) do
|
270
|
+
{
|
271
|
+
foo: 'blah'
|
272
|
+
}
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'returns true' do
|
276
|
+
expect(response).to respond_to(:foo)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context 'when #body does not have key' do
|
281
|
+
|
282
|
+
let(:body) do
|
283
|
+
{}
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'returns false' do
|
287
|
+
expect(response).not_to respond_to(:foo)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
describe '#method_missing' do
|
293
|
+
|
294
|
+
context 'when key in #body' do
|
295
|
+
|
296
|
+
before do
|
297
|
+
allow(response).to receive(:body).and_return(something: 'stuff')
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'returns value' do
|
301
|
+
expect(response.something).to eq('stuff')
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'when not key in #body' do
|
306
|
+
|
307
|
+
it 'raises NoMethodError' do
|
308
|
+
expect {
|
309
|
+
response.bananas
|
310
|
+
}.to raise_error(NoMethodError)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Expedition do
|
4
|
+
|
5
|
+
describe '.new' do
|
6
|
+
|
7
|
+
subject(:client) do
|
8
|
+
described_class.new('example.com', 12345)
|
9
|
+
end
|
10
|
+
|
11
|
+
let!(:mock_client) do
|
12
|
+
double(Expedition::Client)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns new Expedition::Client with supplied host and port' do
|
16
|
+
expect(Expedition::Client).to receive(:new).with('example.com', 12345).and_return(mock_client)
|
17
|
+
expect(client).to eq(mock_client)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.client' do
|
22
|
+
|
23
|
+
subject(:client) do
|
24
|
+
Expedition.client
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns an Expedition::Client' do
|
28
|
+
expect(client).to be_an(Expedition::Client)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns the same instance' do
|
32
|
+
expect(client.object_id).to eq(described_class.client.object_id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
SimpleCov.start
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
11
|
+
require 'expedition'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
15
|
+
config.filter_run focus: true unless ENV['CI']
|
16
|
+
config.order = 'random'
|
17
|
+
config.run_all_when_everything_filtered = true
|
18
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
19
|
+
end
|
20
|
+
|
21
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
metadata
ADDED
@@ -0,0 +1,284 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: expedition
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gabe Evans
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: multi_json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard-bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard-yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rake
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rb-fsevent
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rb-inotify
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rspec
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: terminal-notifier-guard
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: yard
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
description: Expedition is an implementation of the cgminer client protocol. It allows
|
224
|
+
you to write programs that interact with cgminer and cgminer-compatible software.
|
225
|
+
email:
|
226
|
+
- gabe@ga.be
|
227
|
+
executables:
|
228
|
+
- expedition
|
229
|
+
extensions: []
|
230
|
+
extra_rdoc_files: []
|
231
|
+
files:
|
232
|
+
- ".coveralls.yml"
|
233
|
+
- ".gitignore"
|
234
|
+
- ".pryrc"
|
235
|
+
- ".rspec"
|
236
|
+
- ".travis.yml"
|
237
|
+
- ".yardopts"
|
238
|
+
- Gemfile
|
239
|
+
- Guardfile
|
240
|
+
- MIT-LICENSE.txt
|
241
|
+
- README.md
|
242
|
+
- Rakefile
|
243
|
+
- bin/expedition
|
244
|
+
- expedition.gemspec
|
245
|
+
- lib/expedition.rb
|
246
|
+
- lib/expedition/client.rb
|
247
|
+
- lib/expedition/response.rb
|
248
|
+
- lib/expedition/status.rb
|
249
|
+
- lib/expedition/version.rb
|
250
|
+
- spec/expedition/client_spec.rb
|
251
|
+
- spec/expedition/response_spec.rb
|
252
|
+
- spec/expedition_spec.rb
|
253
|
+
- spec/spec_helper.rb
|
254
|
+
homepage: https://github.com/gevans/expedition
|
255
|
+
licenses:
|
256
|
+
- MIT
|
257
|
+
metadata: {}
|
258
|
+
post_install_message:
|
259
|
+
rdoc_options: []
|
260
|
+
require_paths:
|
261
|
+
- lib
|
262
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
263
|
+
requirements:
|
264
|
+
- - ">="
|
265
|
+
- !ruby/object:Gem::Version
|
266
|
+
version: '0'
|
267
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - ">="
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '0'
|
272
|
+
requirements: []
|
273
|
+
rubyforge_project:
|
274
|
+
rubygems_version: 2.2.2
|
275
|
+
signing_key:
|
276
|
+
specification_version: 4
|
277
|
+
summary: Expedition is an implementation of the cgminer client protocol. It allows
|
278
|
+
you to write programs that interact with cgminer and cgminer-compatible software.
|
279
|
+
test_files:
|
280
|
+
- spec/expedition/client_spec.rb
|
281
|
+
- spec/expedition/response_spec.rb
|
282
|
+
- spec/expedition_spec.rb
|
283
|
+
- spec/spec_helper.rb
|
284
|
+
has_rdoc:
|