pachube-stream 0.0.3
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 +4 -0
- data/Gemfile +15 -0
- data/README.rdoc +109 -0
- data/Rakefile +2 -0
- data/autotest/discover.rb +1 -0
- data/examples/subscribe.rb +32 -0
- data/lib/pachube-stream/client.rb +80 -0
- data/lib/pachube-stream/connection.rb +117 -0
- data/lib/pachube-stream/html_request.rb +15 -0
- data/lib/pachube-stream/methods.rb +29 -0
- data/lib/pachube-stream/request.rb +51 -0
- data/lib/pachube-stream/version.rb +3 -0
- data/lib/pachube-stream.rb +15 -0
- data/pachube-stream.gemspec +27 -0
- data/spec/fixtures/pachube/not_authorized.json +6 -0
- data/spec/fixtures/pachube/subscribe.json +5 -0
- data/spec/fixtures/pachube/subscribe_data_stream.json +64 -0
- data/spec/fixtures/pachube/subscribe_request.json +9 -0
- data/spec/pachube_spec.rb +106 -0
- data/spec/spec_helper.rb +51 -0
- metadata +165 -0
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.rdoc
    ADDED
    
    | @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            == PachubeStream
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            PachubeStream gives you an API for the Pachube TCP Stream using EventMachine
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            http://api.pachube.com/v2/beta/#tcp-socket-and-websocket-connections
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            == Quickstart
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              require "pachube-stream"
         | 
| 10 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              Look at the examples directory for exactly that!
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
            == Connection Methods
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            The methods on the connection are what Pachube look for when making a request; this in-turn will 
         | 
| 17 | 
            +
            generate the correct method value in the 'http json'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            === Example
         | 
| 20 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 21 | 
            +
              request = connection.subscribe("/feeds/504")
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              Results In the following JSON request
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              {
         | 
| 26 | 
            +
                "method" : "subscribe",
         | 
| 27 | 
            +
                "resource" : "/feeds/504",
         | 
| 28 | 
            +
                "headers" :
         | 
| 29 | 
            +
                  {
         | 
| 30 | 
            +
                    "X-PachubeApiKey" : "API_KEY"
         | 
| 31 | 
            +
                  },
         | 
| 32 | 
            +
                "token" : "subscribe"
         | 
| 33 | 
            +
              }
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            === Subscribe
         | 
| 37 | 
            +
              
         | 
| 38 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 39 | 
            +
              request = connection.subscribe("/feeds/504")
         | 
| 40 | 
            +
              request.on_datastream do |response|
         | 
| 41 | 
            +
                puts response
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            === Unsubscribe
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 47 | 
            +
              request = connection.unsubscribe("/feeds/504")
         | 
| 48 | 
            +
              request.on_compelete do |response|
         | 
| 49 | 
            +
                puts response
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            === Get
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 55 | 
            +
              request = connection.get("/feeds/504")
         | 
| 56 | 
            +
              request.on_get do |response|
         | 
| 57 | 
            +
                puts response
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            === Put
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 63 | 
            +
              request = connection.put("/feeds/504")
         | 
| 64 | 
            +
              request.on_complete do |response|
         | 
| 65 | 
            +
                puts response
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
              
         | 
| 68 | 
            +
            === Delete
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 71 | 
            +
              request = connection.delete("/feeds/504")
         | 
| 72 | 
            +
              request.on_complete do |response|
         | 
| 73 | 
            +
                puts response
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            === Post
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 79 | 
            +
              request = connection.post("/feeds/504")
         | 
| 80 | 
            +
              request.on_complete do |response|
         | 
| 81 | 
            +
                puts response
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
             | 
| 85 | 
            +
            The way we make a request is to send json in the format of a HTTP request; you only have
         | 
| 86 | 
            +
            to give extra options when you want to provide your own headers, params and body etc;
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            Therefore when using the connection Methods
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            When can create this 'http json request' with PachubeStream::HttpRequest passing in a hash
         | 
| 91 | 
            +
              
         | 
| 92 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 93 | 
            +
              request = connection.put("/feeds/504", PachubeStream::HttpRequest.new(:body => {}, :params => {}, :headers => {}))
         | 
| 94 | 
            +
              
         | 
| 95 | 
            +
              request.on_complete do |response|
         | 
| 96 | 
            +
                puts response
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
            == Defaults:
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            When creating a connection you can specify the host and port these have defaults
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                host                       # => beta.pachube.com
         | 
| 104 | 
            +
                port                       # => 8081
         | 
| 105 | 
            +
                
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            == Respect
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            Respect goes out to the twitter-stream Gem as one took some concepts form that; nice!
         | 
    
        data/Rakefile
    ADDED
    
    
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            Autotest.add_discovery { ["rspec2"] }
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            $: << 'lib' << '../lib'
         | 
| 2 | 
            +
            require 'rubygems'
         | 
| 3 | 
            +
            require 'eventmachine'
         | 
| 4 | 
            +
            require '../lib/pachube-stream'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            EM.run do
         | 
| 7 | 
            +
              connection = PachubeStream::Connection.connect(:api_key => ENV["PACHUBE_API_KEY"])
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              connection.on_reconnect do |timeout, reconnect_retries|
         | 
| 10 | 
            +
                puts timeout
         | 
| 11 | 
            +
                puts reconnect_retries
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
              connection.on_max_reconnects do |timeout, reconnect_retries|
         | 
| 15 | 
            +
                puts timeout
         | 
| 16 | 
            +
                puts reconnect_retries
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              feed = connection.subscribe("/feeds/6643") # random Feed  
         | 
| 20 | 
            +
              
         | 
| 21 | 
            +
              feed.on_datastream do |response|
         | 
| 22 | 
            +
                puts response
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
              
         | 
| 25 | 
            +
              feed.on_complete do |response|
         | 
| 26 | 
            +
                puts response
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              
         | 
| 29 | 
            +
              feed.on_error do |response|
         | 
| 30 | 
            +
                puts response
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,80 @@ | |
| 1 | 
            +
            module PachubeStream
         | 
| 2 | 
            +
              class Client
         | 
| 3 | 
            +
                    
         | 
| 4 | 
            +
                # @param [EventMachine::Connection] conn
         | 
| 5 | 
            +
                # @param [String] api_key
         | 
| 6 | 
            +
                # @param [Hash] options defaults {}
         | 
| 7 | 
            +
                def initialize(conn, api_key, options = {})
         | 
| 8 | 
            +
                  @conn = conn
         | 
| 9 | 
            +
                  @api_key = api_key
         | 
| 10 | 
            +
                  @options = options
         | 
| 11 | 
            +
                  @requests = {}
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                # @param [String] response
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # @return [Hash]
         | 
| 17 | 
            +
                # @todo refactor ugly as Sin
         | 
| 18 | 
            +
                def process_data(response)
         | 
| 19 | 
            +
                  parsed_response = parse_response(response)
         | 
| 20 | 
            +
                  status_ok = parsed_response["status"] && parsed_response["status"] != 200
         | 
| 21 | 
            +
                  if request = @requests[parsed_response["token"]]
         | 
| 22 | 
            +
                    if status_ok
         | 
| 23 | 
            +
                      call_block_for_request(request, parsed_response)
         | 
| 24 | 
            +
                    else
         | 
| 25 | 
            +
                      call_error_for_request_block(request, parsed_response)
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  else
         | 
| 28 | 
            +
                    if status_ok
         | 
| 29 | 
            +
                      @conn.on_response_block.call(parsed_response) if @conn.on_response_block 
         | 
| 30 | 
            +
                    else
         | 
| 31 | 
            +
                      receive_error(parsed_response)
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                # @param [String] response
         | 
| 37 | 
            +
                #
         | 
| 38 | 
            +
                # @return [Hash]
         | 
| 39 | 
            +
                def parse_response(response)
         | 
| 40 | 
            +
                  begin
         | 
| 41 | 
            +
                    Yajl::Parser.parse(response)
         | 
| 42 | 
            +
                  rescue Exception => e
         | 
| 43 | 
            +
                    receive_error("#{e.class}: " + [e.message, e.backtrace].flatten.join("\n\t"))
         | 
| 44 | 
            +
                    @conn.close_connection
         | 
| 45 | 
            +
                    return
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                def receive_error(error)
         | 
| 50 | 
            +
                  @conn.on_error_block.call(error) if @conn.on_error_block
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                # we send the request and also keep the request with the token
         | 
| 54 | 
            +
                # as its key so we can attach callback to requests
         | 
| 55 | 
            +
                def send_request(method, resource, html_request = {}, token = nil, &block)
         | 
| 56 | 
            +
                  @request = Request.new(@api_key, method, resource, html_request, token)
         | 
| 57 | 
            +
                  @requests[@request.token] = @request
         | 
| 58 | 
            +
                  @conn.send_data(@request.to_json)
         | 
| 59 | 
            +
                  @request
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                        
         | 
| 62 | 
            +
                # finds the correct callback based on the token which
         | 
| 63 | 
            +
                # has the method call in its sig
         | 
| 64 | 
            +
                def call_block_for_request(request, parsed_response)
         | 
| 65 | 
            +
                  case request.token.gsub(/:.*/, "")
         | 
| 66 | 
            +
                  when "subscribe" && !parsed_response["body"].nil?
         | 
| 67 | 
            +
                    request.on_datastream_block.call(parsed_response) if request.on_datastream_block
         | 
| 68 | 
            +
                  when "get" && !parsed_response["body"].nil?
         | 
| 69 | 
            +
                    request.on_get_block.call(parsed_response) if request.on_get_block
         | 
| 70 | 
            +
                  else
         | 
| 71 | 
            +
                    request.on_complete_block.call(parsed_response) if request.on_complete_block
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
                
         | 
| 75 | 
            +
                def call_error_for_request_block(request, parsed_response)
         | 
| 76 | 
            +
                  request.on_error_block.call(parsed_response) if request.on_error_block
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| @@ -0,0 +1,117 @@ | |
| 1 | 
            +
            module PachubeStream
         | 
| 2 | 
            +
              class Connection < EventMachine::Connection
         | 
| 3 | 
            +
                include RequestMethods
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                NF_RECONNECT_START = 0.25
         | 
| 6 | 
            +
                NF_RECONNECT_ADD   = 0.25
         | 
| 7 | 
            +
                NF_RECONNECT_MAX   = 16
         | 
| 8 | 
            +
                RECONNECT_MAX   = 320
         | 
| 9 | 
            +
                RETRIES_MAX     = 10
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                attr_accessor :options, :on_init_callback, :api_key, :on_response_block, :on_error_block
         | 
| 12 | 
            +
                attr_accessor :reconnect_callback, :max_reconnects_callback, :nf_last_reconnect, :reconnect_retries
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                # @todo tidy as crap
         | 
| 15 | 
            +
                def self.connect(options = {})
         | 
| 16 | 
            +
                  api_key = options[:api_key]
         | 
| 17 | 
            +
                  raise ArgumentError.new("You need to supply an API Key") unless api_key
         | 
| 18 | 
            +
                  host = options[:host] || "beta.pachube.com"
         | 
| 19 | 
            +
                  port = options[:port] || 8081
         | 
| 20 | 
            +
                  EventMachine.connect host, port, self, options
         | 
| 21 | 
            +
                  rescue EventMachine::ConnectionError => e
         | 
| 22 | 
            +
                    conn = EventMachine::FailedConnection.new(req)
         | 
| 23 | 
            +
                    conn.error = e.message
         | 
| 24 | 
            +
                    conn.fail
         | 
| 25 | 
            +
                    conn
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                
         | 
| 28 | 
            +
                def initialize(options)
         | 
| 29 | 
            +
                  @options = options
         | 
| 30 | 
            +
                  @api_key = options[:api_key]
         | 
| 31 | 
            +
                  @timeout = options[:timeout] || 0
         | 
| 32 | 
            +
                  @reconnect_retries = 0
         | 
| 33 | 
            +
                  @immediate_reconnect = false
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                def client
         | 
| 37 | 
            +
                  @client ||= PachubeStream::Client.new(self, @api_key, @options)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
                  
         | 
| 40 | 
            +
                def post_init
         | 
| 41 | 
            +
                  set_comm_inactivity_timeout @timeout if @timeout > 0
         | 
| 42 | 
            +
                  @on_inited_callback.call if @on_inited_callback
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
                    
         | 
| 45 | 
            +
                def on_reconnect(&block)
         | 
| 46 | 
            +
                  @reconnect_callback = block
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def on_max_reconnects(&block)
         | 
| 50 | 
            +
                  @max_reconnects_callback = block
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                def on_response_block(&block)
         | 
| 54 | 
            +
                  @on_response_block = block
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
                
         | 
| 57 | 
            +
                def on_error_block(&block)
         | 
| 58 | 
            +
                  @on_error_block = block
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def stop
         | 
| 62 | 
            +
                  @gracefully_closed = true
         | 
| 63 | 
            +
                  close_connection
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def immediate_reconnect
         | 
| 67 | 
            +
                  @immediate_reconnect = true
         | 
| 68 | 
            +
                  @gracefully_closed = false
         | 
| 69 | 
            +
                  close_connection
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def unbind
         | 
| 73 | 
            +
                  schedule_reconnect unless @gracefully_closed
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                def receive_data(response)
         | 
| 77 | 
            +
                  client.process_data(response)
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                protected
         | 
| 81 | 
            +
                def schedule_reconnect
         | 
| 82 | 
            +
                  timeout = reconnect_timeout
         | 
| 83 | 
            +
                  @reconnect_retries += 1
         | 
| 84 | 
            +
                  if (timeout <= RECONNECT_MAX) && (@reconnect_retries <= RETRIES_MAX)
         | 
| 85 | 
            +
                    reconnect_after(timeout)
         | 
| 86 | 
            +
                  else
         | 
| 87 | 
            +
                    @max_reconnects_callback.call(timeout, @reconnect_retries) if @max_reconnects_callback
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                def reconnect_after(timeout)
         | 
| 92 | 
            +
                  @reconnect_callback.call(timeout, @reconnect_retries) if @reconnect_callback
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  if timeout == 0
         | 
| 95 | 
            +
                    reconnect @options[:host], @options[:port]
         | 
| 96 | 
            +
                  else
         | 
| 97 | 
            +
                    EventMachine.add_timer(timeout) do
         | 
| 98 | 
            +
                      reconnect @options[:host], @options[:port]
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def reconnect_timeout
         | 
| 104 | 
            +
                  if @immediate_reconnect
         | 
| 105 | 
            +
                    @immediate_reconnect = false
         | 
| 106 | 
            +
                    return 0
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
                  if @nf_last_reconnect
         | 
| 109 | 
            +
                    @nf_last_reconnect += NF_RECONNECT_ADD
         | 
| 110 | 
            +
                  else
         | 
| 111 | 
            +
                    @nf_last_reconnect = NF_RECONNECT_START
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
                  [@nf_last_reconnect, NF_RECONNECT_MAX].min
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
                
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module PachubeStream
         | 
| 2 | 
            +
              class HtmlRequest < Hashie::Dash
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
                property :resource
         | 
| 5 | 
            +
                property :method
         | 
| 6 | 
            +
                property :headers, :default => {}
         | 
| 7 | 
            +
                property :token
         | 
| 8 | 
            +
                property :body
         | 
| 9 | 
            +
                property :params
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
                def api_key=(api_key)
         | 
| 12 | 
            +
                  headers["X-PachubeApiKey"] = api_key
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module PachubeStream
         | 
| 2 | 
            +
              module RequestMethods
         | 
| 3 | 
            +
                
         | 
| 4 | 
            +
                def get(resource, html_request = {}, token = nil, &block)
         | 
| 5 | 
            +
                  client.send_request(:get, resource,  html_request = {}, token, &block)
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                def post(resource, html_request = {}, token  = nil, &block)
         | 
| 9 | 
            +
                  client.send_request(:post, resource,  html_request = {}, token, &block)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                def put(resource, html_request = {}, token = nil, &block)
         | 
| 13 | 
            +
                  client.send_request(:put, resource, html_request = {}, token, &block)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                def delete(resource,html_request = {}, token= nil, &block)
         | 
| 17 | 
            +
                  client.send_request(:delete, resource, html_request = {}, token, &block)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                def subscribe(resource, html_request = {}, token  = nil, &block)
         | 
| 21 | 
            +
                  client.send_request(:subscribe, resource, html_request = {}, token, &block)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
                def unsubsribe(resource, html_request = {}, token = nil, &block)
         | 
| 25 | 
            +
                  client.send_request(:unsubsribe, resource, html_request = {}, token, &block)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            module PachubeStream
         | 
| 2 | 
            +
              class Request
         | 
| 3 | 
            +
                
         | 
| 4 | 
            +
                attr_accessor :on_complete_block, :on_datastream_block, :request, :token, :method, :on_error_block, :on_get_block
         | 
| 5 | 
            +
                
         | 
| 6 | 
            +
                # @param[String] method
         | 
| 7 | 
            +
                # @param[String] html this means headers and body and resource and params
         | 
| 8 | 
            +
                # @param[String] token if you wanted to send a specific token
         | 
| 9 | 
            +
                def initialize(api_key, method, resource, html_request, token = nil)
         | 
| 10 | 
            +
                  @api_key = api_key
         | 
| 11 | 
            +
                  @method = method
         | 
| 12 | 
            +
                  @resource = resource
         | 
| 13 | 
            +
                  @html_request = html_request
         | 
| 14 | 
            +
                  @token = token || generate_token(method)
         | 
| 15 | 
            +
                  generate_html_request(api_key, method, resource, html_request, @token)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                def on_complete(&block)
         | 
| 19 | 
            +
                  @on_complete_block = block
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                def on_datastream(&block)
         | 
| 23 | 
            +
                  @on_datastream_block = block
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                def on_error(&block)
         | 
| 27 | 
            +
                  @on_error_block = block
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                def on_get(&block)
         | 
| 31 | 
            +
                  @on_get_block = block
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                
         | 
| 34 | 
            +
                def to_json
         | 
| 35 | 
            +
                  @request.to_json
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
                    
         | 
| 38 | 
            +
                protected 
         | 
| 39 | 
            +
                def generate_token(method)
         | 
| 40 | 
            +
                  "#{method}:#{UUID.generate}"
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                def generate_html_request(api_key, method, resource, html_request, token)
         | 
| 44 | 
            +
                  @request = HtmlRequest.new(html_request)
         | 
| 45 | 
            +
                  @request.api_key = api_key
         | 
| 46 | 
            +
                  @request[:method] = method
         | 
| 47 | 
            +
                  @request[:resource] = resource
         | 
| 48 | 
            +
                  @request[:token] = token
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module PachubeStream
         | 
| 2 | 
            +
            end
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'eventmachine'
         | 
| 5 | 
            +
            require 'addressable/uri'
         | 
| 6 | 
            +
            require "hashie"
         | 
| 7 | 
            +
            require 'yajl'
         | 
| 8 | 
            +
            require 'json'
         | 
| 9 | 
            +
            require 'uuid'
         | 
| 10 | 
            +
            require 'pachube-stream/methods'
         | 
| 11 | 
            +
            require 'pachube-stream/connection'
         | 
| 12 | 
            +
            require 'pachube-stream/client'
         | 
| 13 | 
            +
            require 'pachube-stream/request'
         | 
| 14 | 
            +
            require 'pachube-stream/html_request'
         | 
| 15 | 
            +
             | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            $:.push File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
            require "pachube-stream/version"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Gem::Specification.new do |s|
         | 
| 6 | 
            +
              s.name        = "pachube-stream"
         | 
| 7 | 
            +
              s.version     = PachubeStream::VERSION
         | 
| 8 | 
            +
              s.platform    = Gem::Platform::RUBY
         | 
| 9 | 
            +
              s.authors     = ["Hookercookerman"]
         | 
| 10 | 
            +
              s.email       = ["hookercookerman@gmail.com"]
         | 
| 11 | 
            +
              s.homepage    = ""
         | 
| 12 | 
            +
              s.summary     = %q{Pachube TCP streaming API}
         | 
| 13 | 
            +
              s.description = %q{Simple Ruby client library for pachube TCP streaming API. Uses EventMachine for connection handling.JSON format only.}
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              s.rubyforge_project = "pachube-stream"
         | 
| 16 | 
            +
              
         | 
| 17 | 
            +
              s.add_dependency "eventmachine", ">= 1.0.0.beta.3"
         | 
| 18 | 
            +
              s.add_dependency "addressable", ">= 2.2.3"
         | 
| 19 | 
            +
              s.add_dependency "hashie", ">= 0.5.1"
         | 
| 20 | 
            +
              s.add_dependency 'yajl-ruby', '~> 0.8.2'
         | 
| 21 | 
            +
              s.add_dependency 'uuid', '~> 2.3.2'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              s.files         = `git ls-files`.split("\n")
         | 
| 24 | 
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         | 
| 25 | 
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         | 
| 26 | 
            +
              s.require_paths = ["lib"]
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
                "body":
         | 
| 3 | 
            +
                {
         | 
| 4 | 
            +
                    "location":
         | 
| 5 | 
            +
                    {
         | 
| 6 | 
            +
                        "lon":-0.0215005874633789,
         | 
| 7 | 
            +
                        "domain":"physical",
         | 
| 8 | 
            +
                        "disposition":"fixed",
         | 
| 9 | 
            +
                        "exposure":"indoor",
         | 
| 10 | 
            +
                        "lat":51.4722148395794
         | 
| 11 | 
            +
                    },
         | 
| 12 | 
            +
                    "title":"CurrentCost meter",
         | 
| 13 | 
            +
                    "datastreams":
         | 
| 14 | 
            +
                    [
         | 
| 15 | 
            +
                        {
         | 
| 16 | 
            +
                            "current_value":"32.2",
         | 
| 17 | 
            +
                            "max_value":"32.3",
         | 
| 18 | 
            +
                            "min_value":"9.3",
         | 
| 19 | 
            +
                            "id":"0",
         | 
| 20 | 
            +
                            "tags":
         | 
| 21 | 
            +
                            [
         | 
| 22 | 
            +
                                "celsius",
         | 
| 23 | 
            +
                                "degrees",
         | 
| 24 | 
            +
                                "temperature"
         | 
| 25 | 
            +
                            ],
         | 
| 26 | 
            +
                            "unit":
         | 
| 27 | 
            +
                            {
         | 
| 28 | 
            +
                                "label":"Celsius",
         | 
| 29 | 
            +
                                "symbol":"C",
         | 
| 30 | 
            +
                                "type":"basicSI"
         | 
| 31 | 
            +
                            },
         | 
| 32 | 
            +
                            "at":"2011-04-20T12:35:42.653484Z"
         | 
| 33 | 
            +
                        },
         | 
| 34 | 
            +
                        {
         | 
| 35 | 
            +
                            "current_value":"309.0",
         | 
| 36 | 
            +
                            "max_value":"12675.0",
         | 
| 37 | 
            +
                            "min_value":"24.0",
         | 
| 38 | 
            +
                            "id":"1",
         | 
| 39 | 
            +
                            "tags":
         | 
| 40 | 
            +
                            [
         | 
| 41 | 
            +
                                "electricity",
         | 
| 42 | 
            +
                                "power",
         | 
| 43 | 
            +
                                "watts"
         | 
| 44 | 
            +
                            ],
         | 
| 45 | 
            +
                            "unit":
         | 
| 46 | 
            +
                            {
         | 
| 47 | 
            +
                                "label":"Watts",
         | 
| 48 | 
            +
                                "symbol":"W",
         | 
| 49 | 
            +
                                "type":"derivedSI"
         | 
| 50 | 
            +
                            },
         | 
| 51 | 
            +
                            "at":"2011-04-20T12:35:42.653484Z"
         | 
| 52 | 
            +
                        }
         | 
| 53 | 
            +
                    ],
         | 
| 54 | 
            +
                    "creator":"http://www.pachube.com/users/sc84647",
         | 
| 55 | 
            +
                    "private":"false",
         | 
| 56 | 
            +
                    "id":6643,
         | 
| 57 | 
            +
                    "version":"1.0.0",
         | 
| 58 | 
            +
                    "updated":"2011-04-20T12:35:42.653484Z",
         | 
| 59 | 
            +
                    "status":"live",
         | 
| 60 | 
            +
                    "feed":"http://api.pachube.com/v2/feeds/6643.json"
         | 
| 61 | 
            +
                },
         | 
| 62 | 
            +
                "resource":"/feeds/6643",
         | 
| 63 | 
            +
                "token":"subscribe:a06d6f30-4d78-012e-e33d-002332cf7bbe"
         | 
| 64 | 
            +
            }
         | 
| @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            require File.expand_path("../spec_helper", __FILE__)
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe "Pachube" do
         | 
| 5 | 
            +
              context "on connection" do
         | 
| 6 | 
            +
                it "should return stream" do
         | 
| 7 | 
            +
                  EM.should_receive(:connect).and_return('TESTING CONNECT')
         | 
| 8 | 
            +
                  stream = PachubeStream::Connection.connect(:api_key => "Testing")
         | 
| 9 | 
            +
                  stream.should == 'TESTING CONNECT'
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                it "should define default properties" do
         | 
| 13 | 
            +
                  EM.should_receive(:connect).with do |host, port, handler, opts|
         | 
| 14 | 
            +
                    host.should == 'beta.pachube.com'
         | 
| 15 | 
            +
                    port.should == 8081
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  stream = PachubeStream::Connection.connect(:api_key => "Testing")
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
              
         | 
| 21 | 
            +
              context "Connection #subscribe" do
         | 
| 22 | 
            +
                attr_reader :stream
         | 
| 23 | 
            +
                before(:each) do
         | 
| 24 | 
            +
                  $data_to_send = read_fixture('pachube/subscribe.json')
         | 
| 25 | 
            +
                  $recieved_data = ''
         | 
| 26 | 
            +
                  $close_connection = false
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                it "should send the 'http_request json request' with the method subscribe'" do
         | 
| 30 | 
            +
                  connect_stream do |connection|
         | 
| 31 | 
            +
                    connection.subscribe("/feeds/100", {}, "token")
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                  Yajl::Parser.parse($recieved_data).should == Yajl::Parser.parse(read_fixture('pachube/subscribe_request.json'))
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                it "should capture response to the on_compelete as that is not a datastream response" do
         | 
| 37 | 
            +
                  connect_stream do |connection|
         | 
| 38 | 
            +
                    subscription = connection.subscribe("/feeds/100", {}, "subscribe:a06d6f30-4d78-012e-e33d-002332cf7bbe")
         | 
| 39 | 
            +
                    subscription.on_complete do |response|
         | 
| 40 | 
            +
                      $data_to_send = read_fixture('pachube/subscribe_data_stream.json')
         | 
| 41 | 
            +
                      response.should eq(Yajl::Parser.parse(read_fixture('pachube/subscribe.json')))
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                
         | 
| 46 | 
            +
                it "should send capture response on_datastream for datastream" do
         | 
| 47 | 
            +
                  $data_to_send = read_fixture('pachube/subscribe_data_stream.json')
         | 
| 48 | 
            +
                  connect_stream do |connection|
         | 
| 49 | 
            +
                    subscription = connection.subscribe("/feeds/100", {}, "subscribe:a06d6f30-4d78-012e-e33d-002332cf7bbe")
         | 
| 50 | 
            +
                    subscription.on_datastream do |response|
         | 
| 51 | 
            +
                      response.should eq(Yajl::Parser.parse(read_fixture('pachube/subscribe_data_stream.json')))
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                it "should capture to the on_error for the request when status code other then 200" do
         | 
| 57 | 
            +
                  $data_to_send = read_fixture('pachube/not_authorized.json')
         | 
| 58 | 
            +
                  connect_stream do |connection|
         | 
| 59 | 
            +
                    subscription = connection.subscribe("/feeds/100", {}, "subscribe:a06d6f30-4d78-012e-e33d-002332cf7bbe")
         | 
| 60 | 
            +
                    subscription.on_error do |response|
         | 
| 61 | 
            +
                      response.should eq(Yajl::Parser.parse(read_fixture('pachube/not_authorized.json')))
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
              
         | 
| 67 | 
            +
              context "network failure" do
         | 
| 68 | 
            +
                before(:each) do
         | 
| 69 | 
            +
                  $close_connection = true
         | 
| 70 | 
            +
                  $data_to_send = ''
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                it "should reconnect with 0.25 at base"  do
         | 
| 74 | 
            +
                  connect_stream do |connection|
         | 
| 75 | 
            +
                    connection.should_receive(:reconnect_after).with(0.25)
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
                
         | 
| 79 | 
            +
                it "should reconnect with linear timeout" do
         | 
| 80 | 
            +
                  connect_stream do |connection|
         | 
| 81 | 
            +
                    connection.nf_last_reconnect = 1
         | 
| 82 | 
            +
                    connection.should_receive(:reconnect_after).with(1.25)
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              
         | 
| 86 | 
            +
                it "should stop reconnecting after 100 times" do
         | 
| 87 | 
            +
                  connect_stream do |connection|
         | 
| 88 | 
            +
                    connection.reconnect_retries = 100
         | 
| 89 | 
            +
                    connection.should_not_receive(:reconnect_after)
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
              
         | 
| 93 | 
            +
                it "should notify after reconnect limit is reached" do
         | 
| 94 | 
            +
                  timeout, retries = nil, nil
         | 
| 95 | 
            +
                  connect_stream do |connection|
         | 
| 96 | 
            +
                    connection.on_max_reconnects do |t, r|
         | 
| 97 | 
            +
                      timeout, retries = t, r
         | 
| 98 | 
            +
                    end
         | 
| 99 | 
            +
                    connection.reconnect_retries = 100
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
                  timeout.should == 0.25
         | 
| 102 | 
            +
                  retries.should == 101
         | 
| 103 | 
            +
                end    
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require "bundler"
         | 
| 3 | 
            +
            Bundler.setup
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require "pachube-stream"
         | 
| 6 | 
            +
            Bundler.require(:test)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            def fixture_path(path)
         | 
| 12 | 
            +
              File.join(File.dirname(__FILE__), 'fixtures', path)
         | 
| 13 | 
            +
            end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            def read_fixture(path)
         | 
| 16 | 
            +
              File.read(fixture_path(path))
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Host = "127.0.0.1"
         | 
| 20 | 
            +
            Port = 9550
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # == What would be awsome to capture the response tcpdump or something and the replay
         | 
| 23 | 
            +
            class PachubeServer < EM::Connection
         | 
| 24 | 
            +
              attr_accessor :data
         | 
| 25 | 
            +
              def receive_data data
         | 
| 26 | 
            +
                $recieved_data = data
         | 
| 27 | 
            +
                send_data $data_to_send
         | 
| 28 | 
            +
                EventMachine.next_tick {
         | 
| 29 | 
            +
                  close_connection if $close_connection
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            def connect_stream(opts={}, &blk)
         | 
| 35 | 
            +
              EM.run {
         | 
| 36 | 
            +
                opts.merge!(:host => Host, :port => Port)
         | 
| 37 | 
            +
                stop_in = opts.delete(:stop_in) || 0.5
         | 
| 38 | 
            +
                unless opts[:start_server] == false
         | 
| 39 | 
            +
                  EM.start_server Host, Port, PachubeServer
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                @stream = PachubeStream::Connection.connect(:api_key => "testing", :host => Host, :port => Port)
         | 
| 42 | 
            +
                blk.call(@stream) if blk
         | 
| 43 | 
            +
                EM.add_timer(stop_in){ EM.stop }
         | 
| 44 | 
            +
              }
         | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            Rspec.configure do |config|   
         | 
| 48 | 
            +
              config.mock_with :rspec
         | 
| 49 | 
            +
              config.filter_run :focus => true
         | 
| 50 | 
            +
              config.run_all_when_everything_filtered = true
         | 
| 51 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,165 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: pachube-stream
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              prerelease: false
         | 
| 5 | 
            +
              segments: 
         | 
| 6 | 
            +
              - 0
         | 
| 7 | 
            +
              - 0
         | 
| 8 | 
            +
              - 3
         | 
| 9 | 
            +
              version: 0.0.3
         | 
| 10 | 
            +
            platform: ruby
         | 
| 11 | 
            +
            authors: 
         | 
| 12 | 
            +
            - Hookercookerman
         | 
| 13 | 
            +
            autorequire: 
         | 
| 14 | 
            +
            bindir: bin
         | 
| 15 | 
            +
            cert_chain: []
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            date: 2011-04-20 00:00:00 +01:00
         | 
| 18 | 
            +
            default_executable: 
         | 
| 19 | 
            +
            dependencies: 
         | 
| 20 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 21 | 
            +
              name: eventmachine
         | 
| 22 | 
            +
              prerelease: false
         | 
| 23 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 24 | 
            +
                none: false
         | 
| 25 | 
            +
                requirements: 
         | 
| 26 | 
            +
                - - ">="
         | 
| 27 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 28 | 
            +
                    segments: 
         | 
| 29 | 
            +
                    - 1
         | 
| 30 | 
            +
                    - 0
         | 
| 31 | 
            +
                    - 0
         | 
| 32 | 
            +
                    - beta
         | 
| 33 | 
            +
                    - 3
         | 
| 34 | 
            +
                    version: 1.0.0.beta.3
         | 
| 35 | 
            +
              type: :runtime
         | 
| 36 | 
            +
              version_requirements: *id001
         | 
| 37 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 38 | 
            +
              name: addressable
         | 
| 39 | 
            +
              prerelease: false
         | 
| 40 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 41 | 
            +
                none: false
         | 
| 42 | 
            +
                requirements: 
         | 
| 43 | 
            +
                - - ">="
         | 
| 44 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 45 | 
            +
                    segments: 
         | 
| 46 | 
            +
                    - 2
         | 
| 47 | 
            +
                    - 2
         | 
| 48 | 
            +
                    - 3
         | 
| 49 | 
            +
                    version: 2.2.3
         | 
| 50 | 
            +
              type: :runtime
         | 
| 51 | 
            +
              version_requirements: *id002
         | 
| 52 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 53 | 
            +
              name: hashie
         | 
| 54 | 
            +
              prerelease: false
         | 
| 55 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 56 | 
            +
                none: false
         | 
| 57 | 
            +
                requirements: 
         | 
| 58 | 
            +
                - - ">="
         | 
| 59 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 60 | 
            +
                    segments: 
         | 
| 61 | 
            +
                    - 0
         | 
| 62 | 
            +
                    - 5
         | 
| 63 | 
            +
                    - 1
         | 
| 64 | 
            +
                    version: 0.5.1
         | 
| 65 | 
            +
              type: :runtime
         | 
| 66 | 
            +
              version_requirements: *id003
         | 
| 67 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 68 | 
            +
              name: yajl-ruby
         | 
| 69 | 
            +
              prerelease: false
         | 
| 70 | 
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 71 | 
            +
                none: false
         | 
| 72 | 
            +
                requirements: 
         | 
| 73 | 
            +
                - - ~>
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 75 | 
            +
                    segments: 
         | 
| 76 | 
            +
                    - 0
         | 
| 77 | 
            +
                    - 8
         | 
| 78 | 
            +
                    - 2
         | 
| 79 | 
            +
                    version: 0.8.2
         | 
| 80 | 
            +
              type: :runtime
         | 
| 81 | 
            +
              version_requirements: *id004
         | 
| 82 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 83 | 
            +
              name: uuid
         | 
| 84 | 
            +
              prerelease: false
         | 
| 85 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 86 | 
            +
                none: false
         | 
| 87 | 
            +
                requirements: 
         | 
| 88 | 
            +
                - - ~>
         | 
| 89 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 90 | 
            +
                    segments: 
         | 
| 91 | 
            +
                    - 2
         | 
| 92 | 
            +
                    - 3
         | 
| 93 | 
            +
                    - 2
         | 
| 94 | 
            +
                    version: 2.3.2
         | 
| 95 | 
            +
              type: :runtime
         | 
| 96 | 
            +
              version_requirements: *id005
         | 
| 97 | 
            +
            description: Simple Ruby client library for pachube TCP streaming API. Uses EventMachine for connection handling.JSON format only.
         | 
| 98 | 
            +
            email: 
         | 
| 99 | 
            +
            - hookercookerman@gmail.com
         | 
| 100 | 
            +
            executables: []
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            extensions: []
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            extra_rdoc_files: []
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            files: 
         | 
| 107 | 
            +
            - .gitignore
         | 
| 108 | 
            +
            - Gemfile
         | 
| 109 | 
            +
            - README.rdoc
         | 
| 110 | 
            +
            - Rakefile
         | 
| 111 | 
            +
            - autotest/discover.rb
         | 
| 112 | 
            +
            - examples/subscribe.rb
         | 
| 113 | 
            +
            - lib/pachube-stream.rb
         | 
| 114 | 
            +
            - lib/pachube-stream/client.rb
         | 
| 115 | 
            +
            - lib/pachube-stream/connection.rb
         | 
| 116 | 
            +
            - lib/pachube-stream/html_request.rb
         | 
| 117 | 
            +
            - lib/pachube-stream/methods.rb
         | 
| 118 | 
            +
            - lib/pachube-stream/request.rb
         | 
| 119 | 
            +
            - lib/pachube-stream/version.rb
         | 
| 120 | 
            +
            - pachube-stream.gemspec
         | 
| 121 | 
            +
            - spec/fixtures/pachube/not_authorized.json
         | 
| 122 | 
            +
            - spec/fixtures/pachube/subscribe.json
         | 
| 123 | 
            +
            - spec/fixtures/pachube/subscribe_data_stream.json
         | 
| 124 | 
            +
            - spec/fixtures/pachube/subscribe_request.json
         | 
| 125 | 
            +
            - spec/pachube_spec.rb
         | 
| 126 | 
            +
            - spec/spec_helper.rb
         | 
| 127 | 
            +
            has_rdoc: true
         | 
| 128 | 
            +
            homepage: ""
         | 
| 129 | 
            +
            licenses: []
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            post_install_message: 
         | 
| 132 | 
            +
            rdoc_options: []
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            require_paths: 
         | 
| 135 | 
            +
            - lib
         | 
| 136 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 137 | 
            +
              none: false
         | 
| 138 | 
            +
              requirements: 
         | 
| 139 | 
            +
              - - ">="
         | 
| 140 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 141 | 
            +
                  segments: 
         | 
| 142 | 
            +
                  - 0
         | 
| 143 | 
            +
                  version: "0"
         | 
| 144 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 145 | 
            +
              none: false
         | 
| 146 | 
            +
              requirements: 
         | 
| 147 | 
            +
              - - ">="
         | 
| 148 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 149 | 
            +
                  segments: 
         | 
| 150 | 
            +
                  - 0
         | 
| 151 | 
            +
                  version: "0"
         | 
| 152 | 
            +
            requirements: []
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            rubyforge_project: pachube-stream
         | 
| 155 | 
            +
            rubygems_version: 1.3.7
         | 
| 156 | 
            +
            signing_key: 
         | 
| 157 | 
            +
            specification_version: 3
         | 
| 158 | 
            +
            summary: Pachube TCP streaming API
         | 
| 159 | 
            +
            test_files: 
         | 
| 160 | 
            +
            - spec/fixtures/pachube/not_authorized.json
         | 
| 161 | 
            +
            - spec/fixtures/pachube/subscribe.json
         | 
| 162 | 
            +
            - spec/fixtures/pachube/subscribe_data_stream.json
         | 
| 163 | 
            +
            - spec/fixtures/pachube/subscribe_request.json
         | 
| 164 | 
            +
            - spec/pachube_spec.rb
         | 
| 165 | 
            +
            - spec/spec_helper.rb
         |