gecko-ess 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.1.0"
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,23 @@
1
+ module Gecko
2
+ class Widget
3
+ class NumberSecondaryStat < Widget
4
+ attr_accessor :primary_text, :primary_value, :primary_prefix, :secondary_text, :secondary_value, :secondary_prefix, :absolute, :type
5
+
6
+ def data_payload
7
+ {:item =>
8
+ [{
9
+ :text => self.primary_text,
10
+ :value => self.primary_value,
11
+ :prefix => self.primary_prefix
12
+ }, {
13
+ :text => self.secondary_text,
14
+ :value => self.secondary_value,
15
+ :prefix => self.secondary_prefix
16
+ }],
17
+ :absolute => self.absolute,
18
+ :type => self.type
19
+ }
20
+ end
21
+ end
22
+ end
23
+ 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,32 @@
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, :prefix => nil}, {:value => nil, :text => nil, :prefix => nil}], :absolute => nil, :type => 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.primary_prefix = "$"
22
+ @widget.secondary_text = 'text B'
23
+ @widget.secondary_value = 2
24
+ @widget.absolute = "true"
25
+ @widget.type = "reverse"
26
+ expect(@widget.payload).to be_a_valid_payload(
27
+ TEST_API_KEY,
28
+ {:item => [{:value => 1, :text => 'text A', :prefix => "$"}, {:value => 2, :text => 'text B', :prefix => nil}], :absolute => "true", :type => "reverse"}
29
+ )
30
+ end
31
+ end
32
+ end