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/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
@@ -0,0 +1,3 @@
1
+ module Gecko
2
+ VERSION = "0.0.1"
3
+ end
@@ -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