From 1ea666f5134d0c9266a115480a34a55b3a9b5f00 Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Sun, 17 Mar 2013 23:53:13 -0700 Subject: [PATCH 01/13] use general slot class to push to all types --- README.mdown | 95 ++++++++---------------------------- Rakefile | 2 +- ducksboard.gemspec | 3 +- lib/ducksboard.rb | 1 + lib/ducksboard/slot.rb | 75 ++++++++++++++++++++++++++++ test/ducksboard/slot_test.rb | 37 ++++++++++++++ test/minitest_helper.rb | 4 ++ 7 files changed, 141 insertions(+), 76 deletions(-) create mode 100644 lib/ducksboard/slot.rb create mode 100644 test/ducksboard/slot_test.rb diff --git a/README.mdown b/README.mdown index 2b28632..126f094 100644 --- a/README.mdown +++ b/README.mdown @@ -2,83 +2,30 @@ ### Configuration -API Key can be set in the environment +API Key can be set in the environment (such as `~/.bashrc`). export DUCKSBOARD_API_KEY='YOURKEY' -or in an initializer +or in an initializer (such as `config/initializers/ducksboard.rb`) Ducksboard.api_key = 'YOURKEY' -### Box - - widget = Ducksboard::Box.new(1234) # Widget numeric id - widget.value = 10 - widget.save - -### Counter - - widget = Ducksboard::Counter.new(1234) - widget.value = 10 - widget.save - -### Image - - widget = Ducksboard::Image.new(1235) - widget.source = "https://dashboard.ducksboard.com/static/accounts/img/logo_small.png" - # or - widget.source = "~/Pictures/logo.png" - widget.caption = "Ducksboard logo!" - widget.timestamp = 1310649204 - widget.save - -### Gauge - - widget = Ducksboard::Gauge.new(1235) - widget.value = 0.93 - widget.save - -### Graph - - # remember that the graph widgets need atleast 2 points before it displays anything - widget = Ducksboard::Graph.new(1236) - widget.timestamp = Time.now.to_i - widget.value = 198 - widget.save - -### Pin - - widget = Ducksboard::Pin.new(1234) - widget.value = 10 - widget.save - -### Timeline - - widget = Ducksboard::Timeline.new(1237) - widget.title = "A Title" - widget.image = "http://url.to.io/some_image.gif" - # or - widget.image = :edited - # any of the following as a string or symbol: orange, red, green, created, edited or deleted - widget.content = "text content" - widget.link = "http://google.com" - -### Leaderboard - - widget1 = Ducksboard::Leaderboard.new(56803) - widget1.linha = [{"name" => 'Titulo 1', "values" => [12,13,14]}, - {"name" => 'Titulo 2', "values" => [12,13,142]}, - ] - widget1.save - -### Pull API - - # You can use the HTTP Pull API to retrieve historical data from any widget. - # It will be returned in a map as per the API (http://dev.ducksboard.com/apidoc/pull-api-http) - - widget = Ducksboard::Gauge.new(1235) - data = widget.since(300)['data'] - # or - data = widget.last_values(15) - # or - data = widget.timespan(:daily, "Europe/London") +### Sending Data + +Data can be sent to slots in formats specified in the [Ducksboard API +documentation](http://dev.ducksboard.com/apidoc/slot-kinds). + +```ruby +# Update the value a slot (ie. counter) +slot = Ducksboard::Slot.new(123) +slot.update(:value => 20) + +# Update a leaderboard +slot = Ducksboard::Slot.new("leaderboard") +slot.update(:value => { + :boards => [ + {:name => "person 1", values => [123, 24.5]}, + {:name => "person 2", values => [224, 21.0]} + ] +}) +``` diff --git a/Rakefile b/Rakefile index 93f8aa3..100a001 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ require 'rake/testtask' Rake::TestTask.new do |t| t.libs << "test" << "lib" - t.test_files = FileList['test/*_test.rb'] + t.test_files = FileList['test/**/*_test.rb'] end task :default => :test diff --git a/ducksboard.gemspec b/ducksboard.gemspec index 2919a94..1ffbe29 100644 --- a/ducksboard.gemspec +++ b/ducksboard.gemspec @@ -10,9 +10,10 @@ Gem::Specification.new do |s| s.license = 'MIT' s.required_ruby_version = '>= 1.8.7' - s.add_runtime_dependency 'httparty', '~> 0.8', '>= 0.8.1' + s.add_runtime_dependency 'httparty', '~> 0.10', '>= 0.10.2' s.add_development_dependency 'rake', '~> 10.0' s.add_development_dependency 'minitest', '~> 4.6.2' + s.add_development_dependency 'mocha', '~> 0.13', '>= 0.13.3' s.post_install_message = <<-DESC Quack! (in real-time)" diff --git a/lib/ducksboard.rb b/lib/ducksboard.rb index b1660cf..11a127f 100644 --- a/lib/ducksboard.rb +++ b/lib/ducksboard.rb @@ -7,6 +7,7 @@ def self.api_key end end +require 'ducksboard/slot' require 'ducksboard/widget' require 'ducksboard/box' require 'ducksboard/counter' diff --git a/lib/ducksboard/slot.rb b/lib/ducksboard/slot.rb new file mode 100644 index 0000000..10c645f --- /dev/null +++ b/lib/ducksboard/slot.rb @@ -0,0 +1,75 @@ +module Ducksboard + class Slot + include ::HTTParty + PUSH_URL = "https://push.ducksboard.com/values" + + attr_accessor :id, :data + + # Initialize a new slot. + # + # id - A slot . + def initialize(id) + @id = id + end + + # Update slot with data. + # + # data - A hash or array of hashes of data to send with the update: + # value - A new value for a slot. + # delta - A change in value for a slot. + # timestamp - A time or unix timestamp(optional). + # + # Returns nothing. + def update(data={}) + data[:timestamp] = time_to_unix(data[:timestamp]) if data[:timestamp] + post(data) + end + + # Deletes all data for a given data source. + # + # Returns nothing. + def destroy + delete + end + + protected + + # Internal: Basic auth hash. + # + # Returns a hash. + def auth + {:username => Ducksboard.api_key, :password => "ducksboard-gem"} + end + + # Internal: Convert time to unix timestamp if needed. + # + # Returns a fixnum. + def time_to_unix(time) + if time.respond_to?(:to_i) + time.to_i + else + time + end + end + + # Internal: Sends http request. + # + # sending_data - A hash converted #to_json before sent (required). + # + # Returns nothing. + def post(sending_data) + self.class.post( + "#{PUSH_URL}/#{id}", + :basic_auth => auth, + :body => sending_data.to_json + ) + end + + # Internal: Send delete request. + # + # Returns nothing. + def delete + self.class.delete("#{PUSH_URL}/#{id}", :basic_auth => auth) + end + end +end diff --git a/test/ducksboard/slot_test.rb b/test/ducksboard/slot_test.rb new file mode 100644 index 0000000..c3a60b6 --- /dev/null +++ b/test/ducksboard/slot_test.rb @@ -0,0 +1,37 @@ +require 'minitest_helper' + +describe Ducksboard::Slot do + subject do + Ducksboard::Slot + end + + it "can initialize with an id" do + slot = Ducksboard::Slot.new(123) + slot.id.must_equal 123 + end + + describe "with a slot" do + let(:slot) { Ducksboard::Slot.new(123) } + + it "sends data" do + data = {:value => 123 } + + slot.expects(:post).with(data) + slot.update(data) + end + + it "ensures timestamp is unix timestamp" do + time = Time.now + unix_time = time.to_i + + slot.expects(:post).with({:timestamp => unix_time}) + slot.update({:timestamp => time}) + end + + it "can be destroyed" do + slot.expects(:delete) + slot.destroy + end + end + +end diff --git a/test/minitest_helper.rb b/test/minitest_helper.rb index ea09eae..0fd1f11 100644 --- a/test/minitest_helper.rb +++ b/test/minitest_helper.rb @@ -1,4 +1,8 @@ +require 'rubygems' +require 'bundler/setup' + require 'minitest/spec' require 'minitest/autorun' +require 'mocha' require 'ducksboard' From 3282cea41932b3285c557f8c420dd2985b59598a Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 10:35:24 -0700 Subject: [PATCH 02/13] add codeclimate --- README.mdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.mdown b/README.mdown index 126f094..7ee2d1c 100644 --- a/README.mdown +++ b/README.mdown @@ -1,5 +1,7 @@ ## Ducksboard API Ruby wrapper +[![Code Climate](https://codeclimate.com/github/jhsu/ducksboard.png)](https://codeclimate.com/github/jhsu/ducksboard) + ### Configuration API Key can be set in the environment (such as `~/.bashrc`). From 156e9657b0721797c81a59faaad6284cde80d2db Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 11:46:41 -0700 Subject: [PATCH 03/13] seperate pull and push and request --- ducksboard.gemspec | 3 ++ lib/ducksboard.rb | 5 +++ lib/ducksboard/pull.rb | 46 +++++++++++++++++++++++++ lib/ducksboard/push.rb | 59 ++++++++++++++++++++++++++++++++ lib/ducksboard/request.rb | 14 ++++++++ lib/ducksboard/slot.rb | 66 ++---------------------------------- test/ducksboard/slot_test.rb | 53 +++++++++++++++++++++++++---- test/minitest_helper.rb | 2 ++ 8 files changed, 178 insertions(+), 70 deletions(-) create mode 100644 lib/ducksboard/pull.rb create mode 100644 lib/ducksboard/push.rb create mode 100644 lib/ducksboard/request.rb diff --git a/ducksboard.gemspec b/ducksboard.gemspec index 1ffbe29..982496e 100644 --- a/ducksboard.gemspec +++ b/ducksboard.gemspec @@ -10,10 +10,13 @@ Gem::Specification.new do |s| s.license = 'MIT' s.required_ruby_version = '>= 1.8.7' + s.add_runtime_dependency 'addressable', '~> 2.3', '>= 2.3.3' s.add_runtime_dependency 'httparty', '~> 0.10', '>= 0.10.2' s.add_development_dependency 'rake', '~> 10.0' s.add_development_dependency 'minitest', '~> 4.6.2' + s.add_development_dependency 'webmock', '~> 1.11', '>= 1.11.0' s.add_development_dependency 'mocha', '~> 0.13', '>= 0.13.3' + s.add_development_dependency 'pry', '~> 0.9', '>= 0.9.2' s.post_install_message = <<-DESC Quack! (in real-time)" diff --git a/lib/ducksboard.rb b/lib/ducksboard.rb index 11a127f..cb2d1f7 100644 --- a/lib/ducksboard.rb +++ b/lib/ducksboard.rb @@ -1,4 +1,5 @@ require 'httparty' +require "addressable/uri" module Ducksboard class << self ; attr_accessor :api_key end @@ -7,6 +8,10 @@ def self.api_key end end +require 'ducksboard/request' +require 'ducksboard/push' +require 'ducksboard/pull' + require 'ducksboard/slot' require 'ducksboard/widget' require 'ducksboard/box' diff --git a/lib/ducksboard/pull.rb b/lib/ducksboard/pull.rb new file mode 100644 index 0000000..9ad8bbb --- /dev/null +++ b/lib/ducksboard/pull.rb @@ -0,0 +1,46 @@ +module Ducksboard + module Pull + include ::HTTParty + include Request + PULL_URL = "https://pull.ducksboard.com/values" + + # Get the last :count values. + # + # options - A hash of options: + # count - A integer of the last :count values to fetch. + # + # Returns a hash response. + def last(options={}) + get("last", options) + end + + # Get data since timestamp. + # + # options - A hash of options: + # seconds - A start time in secods. + # + # Returns a hash response. + def since(options={}) + get("since", options) + end + + # Get data summarized by timespan. + # + # options - A hash of options: + # timespan - A string timespan. + # + def timespan(options={}) + end + + protected + + # Internal: Get request for data. + # + # endpoint - string. + def get(endpoint, params={}) + uri = Addressable::URI.new + uri.query_values = params + HTTParty.get("#{PULL_URL}/#{id}/#{endpoint}?#{uri.query}", :basic_auth => auth) + end + end +end diff --git a/lib/ducksboard/push.rb b/lib/ducksboard/push.rb new file mode 100644 index 0000000..0c61575 --- /dev/null +++ b/lib/ducksboard/push.rb @@ -0,0 +1,59 @@ +module Ducksboard + module Push + include Request + PUSH_URL = "https://push.ducksboard.com/values" + + # Update slot with data. + # + # data - A hash or array of hashes of data to send with the update: + # value - A new value for a slot. + # delta - A change in value for a slot. + # timestamp - A time or unix timestamp(optional). + # + # Returns nothing. + def update(data={}) + data[:timestamp] = time_to_unix(data[:timestamp]) if data[:timestamp] + post(data) + end + + # Deletes all data for a given data source. + # + # Returns nothing. + def destroy + delete + end + + protected + + # Internal: Convert time to unix timestamp if needed. + # + # Returns a fixnum. + def time_to_unix(time) + if time.respond_to?(:to_i) + time.to_i + else + time + end + end + + # Internal: Sends http request. + # + # sending_data - A hash converted #to_json before sent (required). + # + # Returns nothing. + def post(sending_data) + self.class.post( + "#{PUSH_URL}/#{id}", + :basic_auth => auth, + :body => sending_data.to_json + ) + end + + # Internal: Send delete request. + # + # Returns nothing. + def delete + self.class.delete("#{PUSH_URL}/#{id}", :basic_auth => auth) + end + end +end diff --git a/lib/ducksboard/request.rb b/lib/ducksboard/request.rb new file mode 100644 index 0000000..db17ba0 --- /dev/null +++ b/lib/ducksboard/request.rb @@ -0,0 +1,14 @@ +module Ducksboard + module Request + include ::HTTParty + + protected + + # Internal: Basic auth hash. + # + # Returns a hash. + def auth + {:username => Ducksboard.api_key, :password => "ducksboard-gem"} + end + end +end diff --git a/lib/ducksboard/slot.rb b/lib/ducksboard/slot.rb index 10c645f..09e4f20 100644 --- a/lib/ducksboard/slot.rb +++ b/lib/ducksboard/slot.rb @@ -1,9 +1,9 @@ module Ducksboard class Slot - include ::HTTParty - PUSH_URL = "https://push.ducksboard.com/values" + include Push + include Pull - attr_accessor :id, :data + attr_accessor :id # Initialize a new slot. # @@ -11,65 +11,5 @@ class Slot def initialize(id) @id = id end - - # Update slot with data. - # - # data - A hash or array of hashes of data to send with the update: - # value - A new value for a slot. - # delta - A change in value for a slot. - # timestamp - A time or unix timestamp(optional). - # - # Returns nothing. - def update(data={}) - data[:timestamp] = time_to_unix(data[:timestamp]) if data[:timestamp] - post(data) - end - - # Deletes all data for a given data source. - # - # Returns nothing. - def destroy - delete - end - - protected - - # Internal: Basic auth hash. - # - # Returns a hash. - def auth - {:username => Ducksboard.api_key, :password => "ducksboard-gem"} - end - - # Internal: Convert time to unix timestamp if needed. - # - # Returns a fixnum. - def time_to_unix(time) - if time.respond_to?(:to_i) - time.to_i - else - time - end - end - - # Internal: Sends http request. - # - # sending_data - A hash converted #to_json before sent (required). - # - # Returns nothing. - def post(sending_data) - self.class.post( - "#{PUSH_URL}/#{id}", - :basic_auth => auth, - :body => sending_data.to_json - ) - end - - # Internal: Send delete request. - # - # Returns nothing. - def delete - self.class.delete("#{PUSH_URL}/#{id}", :basic_auth => auth) - end end end diff --git a/test/ducksboard/slot_test.rb b/test/ducksboard/slot_test.rb index c3a60b6..dfcade7 100644 --- a/test/ducksboard/slot_test.rb +++ b/test/ducksboard/slot_test.rb @@ -1,18 +1,14 @@ require 'minitest_helper' describe Ducksboard::Slot do - subject do - Ducksboard::Slot - end + let(:slot) { Ducksboard::Slot.new(123) } it "can initialize with an id" do - slot = Ducksboard::Slot.new(123) slot.id.must_equal 123 end - describe "with a slot" do - let(:slot) { Ducksboard::Slot.new(123) } + describe "Push" do it "sends data" do data = {:value => 123 } @@ -32,6 +28,49 @@ slot.expects(:delete) slot.destroy end - end + end # Push + + describe "Pull" do + it "grabs last number of data" do + stub_request(:get, /pull\.ducksboard\.com.*last/).to_return( + :body => <<-RESPONSE, +{ + "count": 15, + "data": [ + { + "timestamp": 1332971928.20006, + "value": 132.0 + } + ] +} + RESPONSE + :headers => {'Content-Type' => 'application/json'}) + response = slot.last() + response.must_be_kind_of Hash + end + + it "grabs data since" do + stub_request(:get, /pull\.ducksboard.com.*since/).to_return( + :body => <<-RESPONSE, +{ + "count": 15, + "data": [ + { + "timestamp": 1332971928.20006, + "value": 132.0 + } + ] +} + RESPONSE + :headers => {'Content-Type' => 'application/json'}) + response = slot.since() + response.must_be_kind_of Hash + end + + it "grabs data by timespan" do + skip "pending implementation" + end + + end # Pull end diff --git a/test/minitest_helper.rb b/test/minitest_helper.rb index 0fd1f11..b5d773a 100644 --- a/test/minitest_helper.rb +++ b/test/minitest_helper.rb @@ -4,5 +4,7 @@ require 'minitest/spec' require 'minitest/autorun' require 'mocha' +require 'webmock/minitest' require 'ducksboard' +require 'pry' From 2bf2e823d188851b097a5c16660b9ab246ca06b2 Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 11:48:51 -0700 Subject: [PATCH 04/13] add travis yml --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..777d8eb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +rvm: + - "1.9.3" + - jruby-19mode + - rbx-19mode + - jruby-18mode + - "1.8.7" From e9a13d3ae992d710a2c1d00e4ea9e7f141833aad Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 11:50:29 -0700 Subject: [PATCH 05/13] add travis image --- README.mdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.mdown b/README.mdown index 7ee2d1c..96e8570 100644 --- a/README.mdown +++ b/README.mdown @@ -1,6 +1,7 @@ ## Ducksboard API Ruby wrapper [![Code Climate](https://codeclimate.com/github/jhsu/ducksboard.png)](https://codeclimate.com/github/jhsu/ducksboard) +[![Build Status](https://travis-ci.org/jhsu/ducksboard.png?branch=simple-slot-push)](https://travis-ci.org/jhsu/ducksboard) ### Configuration From 321cf652553ae94e9ac4cb06cfac865db9815f48 Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 11:51:50 -0700 Subject: [PATCH 06/13] add json dep --- ducksboard.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ducksboard.gemspec b/ducksboard.gemspec index 982496e..18ea481 100644 --- a/ducksboard.gemspec +++ b/ducksboard.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'addressable', '~> 2.3', '>= 2.3.3' s.add_runtime_dependency 'httparty', '~> 0.10', '>= 0.10.2' + s.add_runtime_dependency 'json', '~> 1.7', '>= 1.7.7' s.add_development_dependency 'rake', '~> 10.0' s.add_development_dependency 'minitest', '~> 4.6.2' s.add_development_dependency 'webmock', '~> 1.11', '>= 1.11.0' From df52cd8f69414b93e95964668953f719be4bb71a Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 13:18:19 -0700 Subject: [PATCH 07/13] remove old widget style --- lib/ducksboard.rb | 10 ----- lib/ducksboard/box.rb | 8 ---- lib/ducksboard/counter.rb | 4 -- lib/ducksboard/gauge.rb | 4 -- lib/ducksboard/graph.rb | 7 --- lib/ducksboard/image.rb | 42 ------------------ lib/ducksboard/leaderboard.rb | 20 --------- lib/ducksboard/pin.rb | 7 --- lib/ducksboard/timeline.rb | 43 ------------------- lib/ducksboard/widget.rb | 80 ----------------------------------- 10 files changed, 225 deletions(-) delete mode 100644 lib/ducksboard/box.rb delete mode 100644 lib/ducksboard/counter.rb delete mode 100644 lib/ducksboard/gauge.rb delete mode 100644 lib/ducksboard/graph.rb delete mode 100644 lib/ducksboard/image.rb delete mode 100644 lib/ducksboard/leaderboard.rb delete mode 100644 lib/ducksboard/pin.rb delete mode 100644 lib/ducksboard/timeline.rb delete mode 100644 lib/ducksboard/widget.rb diff --git a/lib/ducksboard.rb b/lib/ducksboard.rb index cb2d1f7..dc7764a 100644 --- a/lib/ducksboard.rb +++ b/lib/ducksboard.rb @@ -11,14 +11,4 @@ def self.api_key require 'ducksboard/request' require 'ducksboard/push' require 'ducksboard/pull' - require 'ducksboard/slot' -require 'ducksboard/widget' -require 'ducksboard/box' -require 'ducksboard/counter' -require 'ducksboard/gauge' -require 'ducksboard/graph' -require 'ducksboard/image' -require 'ducksboard/pin' -require 'ducksboard/timeline' -require 'ducksboard/leaderboard' diff --git a/lib/ducksboard/box.rb b/lib/ducksboard/box.rb deleted file mode 100644 index f7a5531..0000000 --- a/lib/ducksboard/box.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Ducksboard - class Box < Widget - def valid? - @data[:value].is_a?(Integer) - end - end -end - diff --git a/lib/ducksboard/counter.rb b/lib/ducksboard/counter.rb deleted file mode 100644 index e6cb132..0000000 --- a/lib/ducksboard/counter.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Ducksboard - class Counter < Widget - end -end diff --git a/lib/ducksboard/gauge.rb b/lib/ducksboard/gauge.rb deleted file mode 100644 index 0bf0945..0000000 --- a/lib/ducksboard/gauge.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Ducksboard - class Gauge < Widget - end -end diff --git a/lib/ducksboard/graph.rb b/lib/ducksboard/graph.rb deleted file mode 100644 index 9b92c9c..0000000 --- a/lib/ducksboard/graph.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ducksboard - class Graph < Widget - def valid? - @data[:timestamp] && @data[:value] - end - end -end diff --git a/lib/ducksboard/image.rb b/lib/ducksboard/image.rb deleted file mode 100644 index fc7e2d5..0000000 --- a/lib/ducksboard/image.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'base64' -require 'json' -module Ducksboard - class Image < Widget - - def initialize(*args) - super - @data[:value] ||={} - end - - def source - @data[:value][:source] - end - - def source=(image_location) - source_value = if image_location =~ /^http/ - image_location - else - 'data:image/png;base64,' + - Base64.encode64(File.read(File.expand_path(image_location))) - end - @data[:value][:source] = source_value - end - - def caption - @data[:value][:caption] - end - - def caption=(text=nil) - @data[:value][:caption] = caption.to_s - end - - def timestamp - @data[:timestamp] - end - - def timestamp=(time) - @data[:timestamp] = time - end - - end -end diff --git a/lib/ducksboard/leaderboard.rb b/lib/ducksboard/leaderboard.rb deleted file mode 100644 index f62f9c6..0000000 --- a/lib/ducksboard/leaderboard.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'base64' -require 'json' -module Ducksboard - class Leaderboard < Widget - - def initialize(*args) - super - @data[:value] ||={} - end - - def linha - @data[:value][:board] - end - - def linha=(linhaa) - @data[:value][:board] = linhaa - end - - end -end diff --git a/lib/ducksboard/pin.rb b/lib/ducksboard/pin.rb deleted file mode 100644 index acfe943..0000000 --- a/lib/ducksboard/pin.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ducksboard - class Pin < Widget - def valid? - @data[:value].is_a?(Integer) - end - end -end diff --git a/lib/ducksboard/timeline.rb b/lib/ducksboard/timeline.rb deleted file mode 100644 index 2622b1c..0000000 --- a/lib/ducksboard/timeline.rb +++ /dev/null @@ -1,43 +0,0 @@ -module Ducksboard - class Timeline < Widget - - ICONS = { - :orange => "https://app.ducksboard.com/static/img/timeline/orange.gif", - :red => "https://app.ducksboard.com/static/img/timeline/red.gif", - :green => "https://app.ducksboard.com/static/img/timeline/green.gif", - :created => "https://app.ducksboard.com/static/img/timeline/created.png", - :edited => "https://app.ducksboard.com/static/img/timeline/edited.png", - :deleted => "https://app.ducksboard.com/static/img/timeline/deleted.png" - } - - def initialize(*args) - super - @data[:value] ||={} - end - - def title; @data[:title] end - def image; @data[:image] end - def content; @data[:image] end - def link; @data[:image] end - - def title=(text) - @data[:value][:title] = text - end - - def image=(url) - @data[:value][:image] = if url =~ /^http/ - url - else - ICONS[url.to_sym] - end - end - - def content=(text) - @data[:value][:content] = text - end - - def link=(url) - @data[:value][:link] = url - end - end -end diff --git a/lib/ducksboard/widget.rb b/lib/ducksboard/widget.rb deleted file mode 100644 index 4a2b602..0000000 --- a/lib/ducksboard/widget.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'json' -module Ducksboard - class Widget - include ::HTTParty - - attr_accessor :id, :data, :type - - def initialize(id, data={}) - @id = id - @data = data - end - - def value - @data[:value] - end - - def value=(val) - @data[:value] = val - end - - def timestamp - @data[:timestamp] - end - - def timestamp=(time) - @data[:timestamp] = time - end - - def update(data=nil) - @data = data if data - self.class.post("#{PUSH_URI}/#{@id.to_s}", - :basic_auth => auth, - :body => @data.to_json) - end - - def save - if valid? - update.code.to_i == 200 - else - raise "Invalid Data: #{@data.inspect}" - end - end - - def valid? - true - end - - def last_values(number_of_values=3) - pull("last?count=#{number_of_values}") - end - - def since(seconds_ago=3600) - pull("since?seconds=#{seconds_ago.to_i}") - end - - def timespan(timespan=:monthly, timezone="UTC") - pull("timespan?timespan=#{timespan.to_s}&timezone=#{timezone}") - end - - private - - PUSH_URI = "https://push.ducksboard.com/values" - PULL_URI = "https://pull.ducksboard.com/values" - - def auth() - {:username => ::Ducksboard.api_key, :password => "ducksboard-gem"} - end - - def pull(service_uri) - response = self.class.get("#{PULL_URI}/#{@id.to_s}/#{service_uri}", - :basic_auth => auth) - - if response.code.to_i == 200 - JSON.parse(response.body) - else - raise "Unexpected response code: #{response.code}; body: #{response.body}" - end - end - end -end From d3e29f41484a05421edd1b1a51a9218741bc4449 Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 13:32:06 -0700 Subject: [PATCH 08/13] update change log in prep for 1.0.0 --- CHANGELOG.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index b3fdf08..f9f4432 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,3 +1,8 @@ +# 1.0.0 + +- Remove all slot specific code and push and pull all through `Ducksboard::Slot` +- Breaks anything depending on slot type specific classes + # 0.1.5 - #6 Fixed push requests From 30cff66c1a14b1825ee0bc4c5b783348f917cd0d Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Tue, 19 Mar 2013 16:47:52 -0700 Subject: [PATCH 09/13] set version as 1.0.0.beta --- ducksboard.gemspec | 4 +++- lib/ducksboard.rb | 1 + lib/ducksboard/version.rb | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 lib/ducksboard/version.rb diff --git a/ducksboard.gemspec b/ducksboard.gemspec index 18ea481..277a7c5 100644 --- a/ducksboard.gemspec +++ b/ducksboard.gemspec @@ -1,6 +1,8 @@ +require File.join(File.dirname(__FILE__), 'lib/ducksboard/version') + Gem::Specification.new do |s| s.name = 'ducksboard' - s.version = '0.1.5' + s.version = Ducksboard::VERSION s.summary = "API wrapper for ducksboard.com dashboard" s.description = "Ruby API wrapper for ducksboard realtime dashboard using HTTParty" s.authors = ["Joseph Hsu"] diff --git a/lib/ducksboard.rb b/lib/ducksboard.rb index dc7764a..d902963 100644 --- a/lib/ducksboard.rb +++ b/lib/ducksboard.rb @@ -8,6 +8,7 @@ def self.api_key end end +require 'ducksboard/version' require 'ducksboard/request' require 'ducksboard/push' require 'ducksboard/pull' diff --git a/lib/ducksboard/version.rb b/lib/ducksboard/version.rb new file mode 100644 index 0000000..1a5bec4 --- /dev/null +++ b/lib/ducksboard/version.rb @@ -0,0 +1,4 @@ +module Ducksboard + VERSION = Version = "1.0.0.beta" +end + From d7c05ba9929693f08fc4e0969017c29372ad4860 Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Mon, 25 Mar 2013 16:27:35 -0400 Subject: [PATCH 10/13] add timespan and more docs --- README.mdown | 18 ++++++++++- lib/ducksboard/pull.rb | 3 ++ test/ducksboard/slot_test.rb | 58 +++++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/README.mdown b/README.mdown index 96e8570..241b95b 100644 --- a/README.mdown +++ b/README.mdown @@ -13,7 +13,7 @@ or in an initializer (such as `config/initializers/ducksboard.rb`) Ducksboard.api_key = 'YOURKEY' -### Sending Data +### Sending Data (Push API) Data can be sent to slots in formats specified in the [Ducksboard API documentation](http://dev.ducksboard.com/apidoc/slot-kinds). @@ -32,3 +32,19 @@ slot.update(:value => { ] }) ``` + +### Pulling Data (Pull API) + +Fetching data from a slot on Ducksboard. Several convinience methods are +provided to fetch data through the [Ducksboard HTTP Pull +API](http://dev.ducksboard.com/apidoc/pull-api-http/#resource-endpoints). Each +pull returns a hash of data with a data at `response['data']`. + +```ruby +slot = Ducksboard::Slot.new(123) +slot.last(:count => 15) + +slot.since(:seconds => 5 * 60) + +slot.timespan(:timespan => "weekly", :timezone => "UTC") +``` diff --git a/lib/ducksboard/pull.rb b/lib/ducksboard/pull.rb index 9ad8bbb..b6a38df 100644 --- a/lib/ducksboard/pull.rb +++ b/lib/ducksboard/pull.rb @@ -28,8 +28,11 @@ def since(options={}) # # options - A hash of options: # timespan - A string timespan. + # timezone - A string timezone (default: UTC). # + # Returns a hash response. def timespan(options={}) + get("timespan", options) end protected diff --git a/test/ducksboard/slot_test.rb b/test/ducksboard/slot_test.rb index dfcade7..dc14c8c 100644 --- a/test/ducksboard/slot_test.rb +++ b/test/ducksboard/slot_test.rb @@ -68,7 +68,63 @@ end it "grabs data by timespan" do - skip "pending implementation" + stub_request(:get, /pull\.ducksboard.com.*timespan/).to_return( + :body => <<-RESPONSE, +{ + "count": 9, + "data": [ + { + "timestamp": null, + "period": null, + "value": null + }, + { + "timestamp": 1355875200.0, + "period": 3, + "value": null + }, + { + "timestamp": 1355961600.0, + "period": 4, + "value": null + }, + { + "timestamp": 1356048000.0, + "period": 5, + "value": 1.0 + }, + { + "timestamp": 1356134400.0, + "period": 6, + "value": 2.0 + }, + { + "timestamp": 1356220800.0, + "period": 7, + "value": null + }, + { + "timestamp": 1356307200.0, + "period": 1, + "value": 3.0 + }, + { + "timestamp": 1356393600.0, + "period": 2, + "value": null + }, + { + "timestamp": 1356480000.0, + "period": 3, + "value": null + } + ] +} + RESPONSE + :headers => {'Content-Type' => 'application/json'}) + + response = slot.timespan(:timespan => "weekly", :timezone => "UTC") + response.must_be_kind_of(Hash) end end # Pull From f6ee5e60702c7669e89cebbca3ae4c6cf78502fd Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Mon, 25 Mar 2013 16:28:05 -0400 Subject: [PATCH 11/13] add TODO --- README.mdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.mdown b/README.mdown index 241b95b..b5d879c 100644 --- a/README.mdown +++ b/README.mdown @@ -48,3 +48,8 @@ slot.since(:seconds => 5 * 60) slot.timespan(:timespan => "weekly", :timezone => "UTC") ``` + + +### TODO + +- [ ] Would like some integration tests that actually hit the real API From a693e791d041273b68191a3bc4fb0df1cf92d6ab Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Mon, 25 Mar 2013 16:30:08 -0400 Subject: [PATCH 12/13] version bump beta.1 --- CHANGELOG.markdown | 7 +++++-- lib/ducksboard/version.rb | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index f9f4432..ee32937 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,6 +1,9 @@ -# 1.0.0 +# 1.0.0.beta.1 + +- All slot interactions now go through `Ducksboard::Slot` + +Breaking Changes: -- Remove all slot specific code and push and pull all through `Ducksboard::Slot` - Breaks anything depending on slot type specific classes # 0.1.5 diff --git a/lib/ducksboard/version.rb b/lib/ducksboard/version.rb index 1a5bec4..6bdb329 100644 --- a/lib/ducksboard/version.rb +++ b/lib/ducksboard/version.rb @@ -1,4 +1,4 @@ module Ducksboard - VERSION = Version = "1.0.0.beta" + VERSION = Version = "1.0.0.beta.1" end From f96e8a2d3f9cf5a63f8d3eede3d577f3247d19ec Mon Sep 17 00:00:00 2001 From: Joseph Hsu Date: Sun, 5 May 2013 15:37:36 -0400 Subject: [PATCH 13/13] remove todo --- README.mdown | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.mdown b/README.mdown index b5d879c..1501c01 100644 --- a/README.mdown +++ b/README.mdown @@ -49,7 +49,3 @@ slot.since(:seconds => 5 * 60) slot.timespan(:timespan => "weekly", :timezone => "UTC") ``` - -### TODO - -- [ ] Would like some integration tests that actually hit the real API