gecko 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/.gitignore +20 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +91 -0
- data/Rakefile +2 -0
- data/gecko.gemspec +29 -0
- data/lib/gecko.rb +22 -0
- data/lib/gecko/configurator.rb +11 -0
- data/lib/gecko/graph/funnel.rb +67 -0
- data/lib/gecko/graph/geckometer.rb +39 -0
- data/lib/gecko/graph/line.rb +64 -0
- data/lib/gecko/graph/pie.rb +49 -0
- data/lib/gecko/http.rb +79 -0
- data/lib/gecko/version.rb +3 -0
- data/lib/gecko/widget.rb +75 -0
- data/lib/gecko/widget/number_secondary_stat.rb +18 -0
- data/lib/gecko/widget/rag.rb +21 -0
- data/lib/gecko/widget/rag_columns.rb +21 -0
- data/lib/gecko/widget/text.rb +67 -0
- data/spec/gecko/funnel_spec.rb +40 -0
- data/spec/gecko/geckometer_spec.rb +38 -0
- data/spec/gecko/line_spec.rb +42 -0
- data/spec/gecko/number_and_secondary_stat_spec.rb +29 -0
- data/spec/gecko/pie_spec.rb +36 -0
- data/spec/gecko/rag_spec.rb +48 -0
- data/spec/gecko/text_spec.rb +49 -0
- data/spec/gecko_spec.rb +31 -0
- data/spec/helper.rb +25 -0
- data/spec/http_spec.rb +141 -0
- data/spec/support/shared_examples_for_widget.rb +64 -0
- data/spec/widget_spec.rb +172 -0
- metadata +246 -0
data/lib/gecko/http.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'faraday_middleware/multi_json'
|
2
|
+
|
3
|
+
module Gecko
|
4
|
+
class Http
|
5
|
+
def initialize(*args)
|
6
|
+
@connection = Faraday.new(*args) do |connection|
|
7
|
+
connection.response :multi_json, :symbolize_keys => true
|
8
|
+
Gecko.config.connection_builder.call(connection) if Gecko.config.connection_builder.respond_to?(:call)
|
9
|
+
yield connection if block_given?
|
10
|
+
connection.adapter Faraday.default_adapter if connection.builder.handlers.none? { |handler| handler.klass < Faraday::Adapter }
|
11
|
+
end
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def headers
|
16
|
+
{
|
17
|
+
:accept => 'application/json',
|
18
|
+
:user_agent => Gecko.config.http_user_agent
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def encode_body(body)
|
23
|
+
MultiJson.encode(body)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post(url, body, &request_block)
|
27
|
+
Result.new(@connection.post(url, self.encode_body(body), self.headers, &request_block))
|
28
|
+
end
|
29
|
+
|
30
|
+
class Result
|
31
|
+
Error = Struct.new(:text, :status) do
|
32
|
+
def to_s
|
33
|
+
self.text
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :response
|
38
|
+
attr_accessor :response_env
|
39
|
+
|
40
|
+
def initialize(response)
|
41
|
+
@response = response
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_complete(&block)
|
45
|
+
self.response.on_complete do |env|
|
46
|
+
self.response_env = env
|
47
|
+
block.call(self.success?, self)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def response_body
|
52
|
+
self.response.body
|
53
|
+
end
|
54
|
+
|
55
|
+
def success?
|
56
|
+
self.http_200? && !self.error?
|
57
|
+
end
|
58
|
+
|
59
|
+
def http_200?
|
60
|
+
self.response.status == 200
|
61
|
+
end
|
62
|
+
|
63
|
+
def error?
|
64
|
+
self.fetch(:success) != true
|
65
|
+
end
|
66
|
+
|
67
|
+
def error
|
68
|
+
Error.new(self.fetch(:error), self.response.status)
|
69
|
+
end
|
70
|
+
|
71
|
+
def fetch(*keys)
|
72
|
+
keys.inject(self.response_body) do |body_hash, key|
|
73
|
+
break unless body_hash
|
74
|
+
body_hash.fetch(key, nil)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/gecko/widget.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Gecko
|
2
|
+
class Widget
|
3
|
+
attr_reader :data, :keys
|
4
|
+
|
5
|
+
def initialize(*keys, &block)
|
6
|
+
self.keys = *keys
|
7
|
+
@on_update = nil
|
8
|
+
block.call(self) if block
|
9
|
+
raise ArgumentError, "1 or more widget keys are required" if self.keys.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def keys=(*keys)
|
13
|
+
@keys = keys.flatten.compact
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_update(&block)
|
17
|
+
@permanent_on_update = block
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def push_url(key)
|
22
|
+
Gecko.config.api_push_url.gsub(/:widget_key/, key)
|
23
|
+
end
|
24
|
+
|
25
|
+
def update(&on_update)
|
26
|
+
self.push_requests do |push_result, key|
|
27
|
+
push_result.on_complete do |*args|
|
28
|
+
args << key
|
29
|
+
@permanent_on_update.call(*args) if @permanent_on_update.respond_to?(:call)
|
30
|
+
on_update.call(*args) if on_update
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def push_requests(&each_result)
|
36
|
+
self.keys.map do |key|
|
37
|
+
http = Gecko::Http.new
|
38
|
+
push_result = http.post(self.push_url(key), self.payload)
|
39
|
+
each_result.call(push_result, key) if each_result
|
40
|
+
push_result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def config(&block)
|
45
|
+
block.call(self)
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def config!(&block)
|
50
|
+
self.config(&block).update
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def data_payload
|
55
|
+
{}
|
56
|
+
end
|
57
|
+
|
58
|
+
def payload
|
59
|
+
{
|
60
|
+
:api_key => Gecko.config.api_key,
|
61
|
+
:data => self.data_payload
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'gecko/widget/number_secondary_stat'
|
68
|
+
require 'gecko/widget/rag'
|
69
|
+
require 'gecko/widget/rag_columns'
|
70
|
+
require 'gecko/widget/text'
|
71
|
+
|
72
|
+
require 'gecko/graph/pie'
|
73
|
+
require 'gecko/graph/geckometer'
|
74
|
+
require 'gecko/graph/funnel'
|
75
|
+
require 'gecko/graph/line'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Gecko
|
2
|
+
class Widget
|
3
|
+
class NumberSecondaryStat < Widget
|
4
|
+
attr_accessor :primary_text, :primary_value, :secondary_text, :secondary_value
|
5
|
+
|
6
|
+
def data_payload
|
7
|
+
{:item =>
|
8
|
+
[{
|
9
|
+
:text => self.primary_text,
|
10
|
+
:value => self.primary_value
|
11
|
+
}, {
|
12
|
+
:text => self.secondary_text,
|
13
|
+
:value => self.secondary_value
|
14
|
+
}]}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Gecko
|
2
|
+
class Widget
|
3
|
+
class Rag < Widget
|
4
|
+
attr_accessor :green_text, :green_value, :amber_text, :amber_value, :red_text, :red_value
|
5
|
+
|
6
|
+
def data_payload
|
7
|
+
{:item =>
|
8
|
+
[{
|
9
|
+
:text => self.red_text,
|
10
|
+
:value => self.red_value
|
11
|
+
}, {
|
12
|
+
:text => self.amber_text,
|
13
|
+
:value => self.amber_value
|
14
|
+
}, {
|
15
|
+
:text => self.green_text,
|
16
|
+
:value => self.green_value
|
17
|
+
}]}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Gecko
|
2
|
+
class Widget
|
3
|
+
class RagColumns < Widget
|
4
|
+
attr_accessor :green_text, :green_value, :amber_text, :amber_value, :red_text, :red_value
|
5
|
+
|
6
|
+
def data_payload
|
7
|
+
{:item =>
|
8
|
+
[{
|
9
|
+
:text => self.red_text,
|
10
|
+
:value => self.red_value
|
11
|
+
}, {
|
12
|
+
:text => self.amber_text,
|
13
|
+
:value => self.amber_value
|
14
|
+
}, {
|
15
|
+
:text => self.green_text,
|
16
|
+
:value => self.green_value
|
17
|
+
}]}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Gecko
|
2
|
+
class Widget
|
3
|
+
class Text < Widget
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
class Item
|
7
|
+
TYPES = {
|
8
|
+
:normal => 0,
|
9
|
+
:alert => 1,
|
10
|
+
:info => 2
|
11
|
+
}
|
12
|
+
attr_accessor :text
|
13
|
+
attr_reader :type
|
14
|
+
|
15
|
+
def initialize(text = nil, type = :normal)
|
16
|
+
self.text = text
|
17
|
+
self.type = type
|
18
|
+
end
|
19
|
+
|
20
|
+
def type=(type)
|
21
|
+
@type = if type.kind_of?(Numeric)
|
22
|
+
TYPES.values.include?(type) ? type : nil
|
23
|
+
else
|
24
|
+
TYPES.fetch(type, nil)
|
25
|
+
end
|
26
|
+
@type or raise ArgumentError, "#{type} is not a valid text type"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(*args, &block)
|
31
|
+
super
|
32
|
+
@items = []
|
33
|
+
end
|
34
|
+
|
35
|
+
def reset
|
36
|
+
@items.clear
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def each(&block)
|
41
|
+
@items.each(&block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def add(*args)
|
45
|
+
@items.push(Item.new(*args))
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](index)
|
49
|
+
@items[index]
|
50
|
+
end
|
51
|
+
|
52
|
+
def []=(index, *args)
|
53
|
+
@items[index] = Item.new(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete(index)
|
57
|
+
@items.delete_at(index)
|
58
|
+
end
|
59
|
+
|
60
|
+
def data_payload
|
61
|
+
{
|
62
|
+
:item => self.map{ |item| {:text => item.text, :type => item.type} }
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Gecko::Widget::Funnel do
|
4
|
+
it_behaves_like "a Gecko::Widget"
|
5
|
+
|
6
|
+
describe '#payload' do
|
7
|
+
before(:each) do
|
8
|
+
@widget = described_class.new('widget_key')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be empty by default' do
|
12
|
+
expect(@widget.payload).to be_a_valid_payload(
|
13
|
+
TEST_API_KEY,
|
14
|
+
{
|
15
|
+
:type => :standard,
|
16
|
+
:percentage => :show,
|
17
|
+
:item => []
|
18
|
+
}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should be correct hash when values assigned' do
|
23
|
+
@widget.hide_percentage
|
24
|
+
@widget.reverse
|
25
|
+
@widget.add(100, 'benjamin')
|
26
|
+
@widget.add(1, 'washington')
|
27
|
+
expect(@widget.payload).to be_a_valid_payload(
|
28
|
+
TEST_API_KEY,
|
29
|
+
{
|
30
|
+
:type => :reverse,
|
31
|
+
:percentage => :hide,
|
32
|
+
:item => [
|
33
|
+
{:value => 100, :label => 'benjamin'},
|
34
|
+
{:value => 1, :label => 'washington'}
|
35
|
+
]
|
36
|
+
}
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Gecko::Widget::Geckometer do
|
4
|
+
it_behaves_like "a Gecko::Widget"
|
5
|
+
|
6
|
+
describe '#payload' do
|
7
|
+
before(:each) do
|
8
|
+
@widget = described_class.new('widget_key')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be empty by default' do
|
12
|
+
expect(@widget.payload).to be_a_valid_payload(
|
13
|
+
TEST_API_KEY,
|
14
|
+
{
|
15
|
+
:item => nil,
|
16
|
+
:min => {:value => nil, :text => nil},
|
17
|
+
:max => {:value => nil, :text => nil}
|
18
|
+
}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should be correct hash when values assigned' do
|
23
|
+
@widget.min_value = 0
|
24
|
+
@widget.max_value = 100
|
25
|
+
@widget.min_text = 'min'
|
26
|
+
@widget.max_text = 'max'
|
27
|
+
@widget.value = 50
|
28
|
+
expect(@widget.payload).to be_a_valid_payload(
|
29
|
+
TEST_API_KEY,
|
30
|
+
{
|
31
|
+
:item => 50,
|
32
|
+
:min => {:value => 0, :text => 'min'},
|
33
|
+
:max => {:value => 100, :text => 'max'}
|
34
|
+
}
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Gecko::Widget::Line do
|
4
|
+
it_behaves_like "a Gecko::Widget"
|
5
|
+
|
6
|
+
describe '#payload' do
|
7
|
+
before(:each) do
|
8
|
+
@widget = described_class.new('widget_key')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be empty by default' do
|
12
|
+
expect(@widget.payload).to be_a_valid_payload(
|
13
|
+
TEST_API_KEY,
|
14
|
+
{
|
15
|
+
:item => [],
|
16
|
+
:settings => {
|
17
|
+
:axisx => [],
|
18
|
+
:axisy => [],
|
19
|
+
:colour => nil
|
20
|
+
}
|
21
|
+
}
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should be correct hash when values assigned' do
|
26
|
+
@widget.x_axis = [1, 2, 3]
|
27
|
+
@widget.y_axis = %w(a b c)
|
28
|
+
@widget.add(5,6,7)
|
29
|
+
expect(@widget.payload).to be_a_valid_payload(
|
30
|
+
TEST_API_KEY,
|
31
|
+
{
|
32
|
+
:item => [5, 6, 7],
|
33
|
+
:settings => {
|
34
|
+
:axisx => [1, 2, 3],
|
35
|
+
:axisy => ['a', 'b', 'c'],
|
36
|
+
:colour => nil
|
37
|
+
}
|
38
|
+
}
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Gecko::Widget::NumberSecondaryStat do
|
4
|
+
it_behaves_like "a Gecko::Widget"
|
5
|
+
|
6
|
+
describe '#payload' do
|
7
|
+
before(:each) do
|
8
|
+
@widget = described_class.new('widget_key')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be empty by default' do
|
12
|
+
expect(@widget.payload).to be_a_valid_payload(
|
13
|
+
TEST_API_KEY,
|
14
|
+
{:item => [{:value => nil, :text => nil}, {:value => nil, :text => nil}]}
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be correct hash when values assigned' do
|
19
|
+
@widget.primary_text = 'text A'
|
20
|
+
@widget.primary_value = 1
|
21
|
+
@widget.secondary_text = 'text B'
|
22
|
+
@widget.secondary_value = 2
|
23
|
+
expect(@widget.payload).to be_a_valid_payload(
|
24
|
+
TEST_API_KEY,
|
25
|
+
{:item => [{:value => 1, :text => 'text A'}, {:value => 2, :text => 'text B'}]}
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|