mqtt_pipe 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +14 -0
 - data/Gemfile +4 -0
 - data/LICENSE.txt +22 -0
 - data/README.md +43 -0
 - data/Rakefile +2 -0
 - data/examples/receiver.rb +9 -0
 - data/examples/sender.rb +13 -0
 - data/lib/mqtt_pipe.rb +16 -0
 - data/lib/mqtt_pipe/config.rb +31 -0
 - data/lib/mqtt_pipe/listener.rb +57 -0
 - data/lib/mqtt_pipe/packer.rb +83 -0
 - data/lib/mqtt_pipe/pipe.rb +88 -0
 - data/lib/mqtt_pipe/types.rb +11 -0
 - data/lib/mqtt_pipe/types/array.rb +36 -0
 - data/lib/mqtt_pipe/types/class.rb +9 -0
 - data/lib/mqtt_pipe/types/color.rb +17 -0
 - data/lib/mqtt_pipe/types/false.rb +17 -0
 - data/lib/mqtt_pipe/types/float.rb +17 -0
 - data/lib/mqtt_pipe/types/integer.rb +39 -0
 - data/lib/mqtt_pipe/types/nil.rb +17 -0
 - data/lib/mqtt_pipe/types/string.rb +30 -0
 - data/lib/mqtt_pipe/types/time.rb +17 -0
 - data/lib/mqtt_pipe/types/true.rb +17 -0
 - data/lib/mqtt_pipe/types/type.rb +36 -0
 - data/lib/mqtt_pipe/version.rb +3 -0
 - data/mqtt_pipe.gemspec +26 -0
 - data/spec/config_spec.rb +27 -0
 - data/spec/listener_spec.rb +87 -0
 - data/spec/packer_spec.rb +264 -0
 - data/spec/pipe_spec.rb +9 -0
 - metadata +135 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 93caadb951ff60325a712d56794e4431adbcf621
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: b9a8f6b3b8a31d2925601444bad95bb054e00c5e
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: bf62b6c097b52d0770b64b5bf63dc299a399120a525eb4682b03a92f74d74ce3734fe6221c6008c9620774d4c3c28e009b4196d1a0492f822886fbe83b53e645
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9e8cf7c06b4e8a625bff2944337bbf90bb8b180f16e898d1127417a47fc34641f030baec5fb0f0e860023eed030f268bfde664a318ed4de36695843efc30e292
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2015 Sebastian Lindberg
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            MIT License
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            This gem wraps the [MQTT gem](https://github.com/njh/ruby-mqtt) and adds a serializer for simple data structures.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 10 
     | 
    
         
            +
            gem 'mqtt_pipe'
         
     | 
| 
      
 11 
     | 
    
         
            +
            ```
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                $ gem install mqtt_pipe
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 24 
     | 
    
         
            +
            pipe = MQTTPipe.create do
         
     | 
| 
      
 25 
     | 
    
         
            +
              on 'hello/world/#' do |message, id|
         
     | 
| 
      
 26 
     | 
    
         
            +
                p message, id
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            pipe.open 'test.mosquitto.org', port: 1883 do
         
     | 
| 
      
 31 
     | 
    
         
            +
              100.times do |i|
         
     | 
| 
      
 32 
     | 
    
         
            +
                send "hello/world/#{i}", Time.now
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
      
 35 
     | 
    
         
            +
            ```
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            1. Fork it ( https://github.com/[my-github-username]/mqtt_pipe/fork )
         
     | 
| 
      
 40 
     | 
    
         
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 41 
     | 
    
         
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         
     | 
| 
      
 42 
     | 
    
         
            +
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 43 
     | 
    
         
            +
            5. Create a new Pull Request
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/examples/sender.rb
    ADDED
    
    
    
        data/lib/mqtt_pipe.rb
    ADDED
    
    | 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'mqtt'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'mqtt_pipe/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'mqtt_pipe/types'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'mqtt_pipe/packer'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'mqtt_pipe/config'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'mqtt_pipe/listener'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'mqtt_pipe/pipe'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 11 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def create &block
         
     | 
| 
      
 14 
     | 
    
         
            +
                Pipe.new &block
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              
         
     | 
| 
      
 3 
     | 
    
         
            +
              ##
         
     | 
| 
      
 4 
     | 
    
         
            +
              # An instance of Config is used as the context in which
         
     | 
| 
      
 5 
     | 
    
         
            +
              # the pipe is configured.
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Config
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_reader :listeners
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @listeners = []
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                ##
         
     | 
| 
      
 15 
     | 
    
         
            +
                # Subscribe to a topic and attatch an action that will
         
     | 
| 
      
 16 
     | 
    
         
            +
                # be called once a message with a matching topic is 
         
     | 
| 
      
 17 
     | 
    
         
            +
                # received.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def on topic, &action
         
     | 
| 
      
 20 
     | 
    
         
            +
                  raise ArgumentError, 'No block given' if action.nil?
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @listeners << Listener.new(topic, &action)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
                
         
     | 
| 
      
 24 
     | 
    
         
            +
                ##
         
     | 
| 
      
 25 
     | 
    
         
            +
                # Subscribe to all topics
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
                def on_anything &action
         
     | 
| 
      
 28 
     | 
    
         
            +
                  on '#', &action
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              
         
     | 
| 
      
 3 
     | 
    
         
            +
              ##
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Used to store topics along with their actions. 
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Contains conveniens methods for matching the topic to a
         
     | 
| 
      
 6 
     | 
    
         
            +
              # given string as well as calling the action.
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Listener
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :topic, :pattern
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                ##
         
     | 
| 
      
 12 
     | 
    
         
            +
                # The listener requires a topic string and a callable 
         
     | 
| 
      
 13 
     | 
    
         
            +
                # action to initialize.
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                # An ArgumentError is raised if no action is given
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                def initialize topic, &action
         
     | 
| 
      
 18 
     | 
    
         
            +
                  raise ArgumentError, 'No block given' if action.nil?
         
     | 
| 
      
 19 
     | 
    
         
            +
                  
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @topic = topic
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @action = action
         
     | 
| 
      
 22 
     | 
    
         
            +
                  
         
     | 
| 
      
 23 
     | 
    
         
            +
                  pattern = topic.gsub('*', '([^/]+)').gsub('/#', '/?(.*)')
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @pattern = %r{^#{pattern}$}
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
                ##
         
     | 
| 
      
 28 
     | 
    
         
            +
                # Check if a given topic string matches the listener 
         
     | 
| 
      
 29 
     | 
    
         
            +
                # topic.
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                # Returns an array containing any matched sections of
         
     | 
| 
      
 32 
     | 
    
         
            +
                # topic, if there was a match. False otherwise.
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def match topic
         
     | 
| 
      
 35 
     | 
    
         
            +
                  m = @pattern.match topic
         
     | 
| 
      
 36 
     | 
    
         
            +
                  m.nil? ? false : m.captures
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                ##
         
     | 
| 
      
 40 
     | 
    
         
            +
                # Returns true if the topic matches listener topic 
         
     | 
| 
      
 41 
     | 
    
         
            +
                # Otherwise false.
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                def === topic
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @pattern === topic
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                ##
         
     | 
| 
      
 48 
     | 
    
         
            +
                # Call the listener action
         
     | 
| 
      
 49 
     | 
    
         
            +
                
         
     | 
| 
      
 50 
     | 
    
         
            +
                def call *args
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #raise ArgumentError, 'No value provided' if args.empty?
         
     | 
| 
      
 52 
     | 
    
         
            +
                  @action.call *args
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                alias_method :run, :call
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,83 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              
         
     | 
| 
      
 3 
     | 
    
         
            +
              ##
         
     | 
| 
      
 4 
     | 
    
         
            +
              # The packer module is used to pack/unpack classes that
         
     | 
| 
      
 5 
     | 
    
         
            +
              # supports it.
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Packer
         
     | 
| 
      
 8 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                ##
         
     | 
| 
      
 11 
     | 
    
         
            +
                # Raised when the packet being unpacked is badly 
         
     | 
| 
      
 12 
     | 
    
         
            +
                # formatted.
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                class FormatError < StandardError; end
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                ##
         
     | 
| 
      
 17 
     | 
    
         
            +
                # Used to signal the end of a packet as it is being 
         
     | 
| 
      
 18 
     | 
    
         
            +
                # unpacked.
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                class EndOfPacket < StandardError; end
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                # Use the refinements made to the supported classes
         
     | 
| 
      
 23 
     | 
    
         
            +
                
         
     | 
| 
      
 24 
     | 
    
         
            +
                using Types
         
     | 
| 
      
 25 
     | 
    
         
            +
                    
         
     | 
| 
      
 26 
     | 
    
         
            +
                ##
         
     | 
| 
      
 27 
     | 
    
         
            +
                # Packs the arguments acording to their type.
         
     | 
| 
      
 28 
     | 
    
         
            +
                #
         
     | 
| 
      
 29 
     | 
    
         
            +
                # An ArgumentError is raised if any given class does
         
     | 
| 
      
 30 
     | 
    
         
            +
                # not support packing.
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                def pack *values
         
     | 
| 
      
 33 
     | 
    
         
            +
                  values.map{|value| value.to_packed }.join
         
     | 
| 
      
 34 
     | 
    
         
            +
                rescue NoMethodError
         
     | 
| 
      
 35 
     | 
    
         
            +
                  raise ArgumentError, 'Unknown input format'
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
                 
         
     | 
| 
      
 38 
     | 
    
         
            +
                alias_method :[], :pack
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                ##
         
     | 
| 
      
 42 
     | 
    
         
            +
                # Unpacks a serialized object and returns an array of
         
     | 
| 
      
 43 
     | 
    
         
            +
                # the original values.
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                def unpack raw, limit: nil
         
     | 
| 
      
 46 
     | 
    
         
            +
                  raw = StringIO.new raw unless raw.respond_to? :read
         
     | 
| 
      
 47 
     | 
    
         
            +
                  result = []
         
     | 
| 
      
 48 
     | 
    
         
            +
                  
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # Either loop infinately or the number of times 
         
     | 
| 
      
 50 
     | 
    
         
            +
                  # specified by limit
         
     | 
| 
      
 51 
     | 
    
         
            +
                  
         
     | 
| 
      
 52 
     | 
    
         
            +
                  (limit.nil? ? loop : limit.times).each do
         
     | 
| 
      
 53 
     | 
    
         
            +
                    result << unpack_single(raw)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  
         
     | 
| 
      
 56 
     | 
    
         
            +
                  return result
         
     | 
| 
      
 57 
     | 
    
         
            +
                rescue EndOfPacket
         
     | 
| 
      
 58 
     | 
    
         
            +
                  return result
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
                
         
     | 
| 
      
 61 
     | 
    
         
            +
                ##
         
     | 
| 
      
 62 
     | 
    
         
            +
                # A simple helper method to read a given number of bytes
         
     | 
| 
      
 63 
     | 
    
         
            +
                # +from+ IO object and format them +as+ anything 
         
     | 
| 
      
 64 
     | 
    
         
            +
                # supported by Array#unpack.
         
     | 
| 
      
 65 
     | 
    
         
            +
                
         
     | 
| 
      
 66 
     | 
    
         
            +
                def read_packed_bytes n = 1, from:, as: 'C'
         
     | 
| 
      
 67 
     | 
    
         
            +
                  raw = from.read(n)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  raise FormatError if raw.nil? or raw.length != n
         
     | 
| 
      
 69 
     | 
    
         
            +
                  
         
     | 
| 
      
 70 
     | 
    
         
            +
                  raw.unpack(as).first
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
                
         
     | 
| 
      
 73 
     | 
    
         
            +
                private
         
     | 
| 
      
 74 
     | 
    
         
            +
                
         
     | 
| 
      
 75 
     | 
    
         
            +
                def unpack_single raw
         
     | 
| 
      
 76 
     | 
    
         
            +
                  code = raw.read 1
         
     | 
| 
      
 77 
     | 
    
         
            +
                  raise EndOfPacket if code.nil?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  
         
     | 
| 
      
 79 
     | 
    
         
            +
                  type = code.unpack(?C).first
         
     | 
| 
      
 80 
     | 
    
         
            +
                  Types::Type.lookup(type).from_packed type, raw
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,88 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              
         
     | 
| 
      
 3 
     | 
    
         
            +
              ##
         
     | 
| 
      
 4 
     | 
    
         
            +
              # The actual wrapper class for MQTT
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Pipe
         
     | 
| 
      
 7 
     | 
    
         
            +
                
         
     | 
| 
      
 8 
     | 
    
         
            +
                ##
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Raised when the connection unexpectedly lost.
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                class ConnectionError < StandardError; end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize &block      
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @config = Config.new  
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @config.instance_eval &block unless block.nil?
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                ##
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Open the pipe
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                def open host, port: 1883, &block
         
     | 
| 
      
 23 
     | 
    
         
            +
                  MQTT::Client.connect host: host, port: port do |client|
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
                    # Subscribe
         
     | 
| 
      
 26 
     | 
    
         
            +
                    topics = @config.listeners.map{|listener| listener.topic }
         
     | 
| 
      
 27 
     | 
    
         
            +
                    listener_thread = nil
         
     | 
| 
      
 28 
     | 
    
         
            +
                    
         
     | 
| 
      
 29 
     | 
    
         
            +
                    unless topics.empty?
         
     | 
| 
      
 30 
     | 
    
         
            +
                      listener_thread = Thread.new do
         
     | 
| 
      
 31 
     | 
    
         
            +
                        client.get do |topic, data|
         
     | 
| 
      
 32 
     | 
    
         
            +
                          begin
         
     | 
| 
      
 33 
     | 
    
         
            +
                            unpacked_data = Packer.unpack data
         
     | 
| 
      
 34 
     | 
    
         
            +
                            
         
     | 
| 
      
 35 
     | 
    
         
            +
                            @config.listeners.each do |listener|
         
     | 
| 
      
 36 
     | 
    
         
            +
                              if m = listener.match(topic)
         
     | 
| 
      
 37 
     | 
    
         
            +
                                listener.call unpacked_data, *m
         
     | 
| 
      
 38 
     | 
    
         
            +
                              end
         
     | 
| 
      
 39 
     | 
    
         
            +
                            end
         
     | 
| 
      
 40 
     | 
    
         
            +
                            
         
     | 
| 
      
 41 
     | 
    
         
            +
                          rescue Packer::FormatError
         
     | 
| 
      
 42 
     | 
    
         
            +
                            # TODO: Handle more gracefully
         
     | 
| 
      
 43 
     | 
    
         
            +
                            puts 'Could not parse data!'
         
     | 
| 
      
 44 
     | 
    
         
            +
                            next
         
     | 
| 
      
 45 
     | 
    
         
            +
                          end
         
     | 
| 
      
 46 
     | 
    
         
            +
                        end
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
                      
         
     | 
| 
      
 49 
     | 
    
         
            +
                      client.subscribe *topics
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                              
         
     | 
| 
      
 52 
     | 
    
         
            +
                    unless block.nil?
         
     | 
| 
      
 53 
     | 
    
         
            +
                      context = Context.new client
         
     | 
| 
      
 54 
     | 
    
         
            +
                      
         
     | 
| 
      
 55 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 56 
     | 
    
         
            +
                        context.instance_eval &block
         
     | 
| 
      
 57 
     | 
    
         
            +
                      rescue ConnectionError
         
     | 
| 
      
 58 
     | 
    
         
            +
                        
         
     | 
| 
      
 59 
     | 
    
         
            +
                        puts 'Need to reconnect'
         
     | 
| 
      
 60 
     | 
    
         
            +
                      rescue Interrupt
         
     | 
| 
      
 61 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 62 
     | 
    
         
            +
                        listener_thread.exit unless topics.empty?
         
     | 
| 
      
 63 
     | 
    
         
            +
                      end
         
     | 
| 
      
 64 
     | 
    
         
            +
                    
         
     | 
| 
      
 65 
     | 
    
         
            +
                    else
         
     | 
| 
      
 66 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 67 
     | 
    
         
            +
                        listener_thread.join unless topics.empty?
         
     | 
| 
      
 68 
     | 
    
         
            +
                      rescue Interrupt
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
                
         
     | 
| 
      
 74 
     | 
    
         
            +
                private
         
     | 
| 
      
 75 
     | 
    
         
            +
                
         
     | 
| 
      
 76 
     | 
    
         
            +
                class Context
         
     | 
| 
      
 77 
     | 
    
         
            +
                  def initialize client
         
     | 
| 
      
 78 
     | 
    
         
            +
                    @client = client
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  
         
     | 
| 
      
 81 
     | 
    
         
            +
                  def send topic, *data
         
     | 
| 
      
 82 
     | 
    
         
            +
                    raise ConnectionError unless @client.connected?
         
     | 
| 
      
 83 
     | 
    
         
            +
                    @client.publish topic, Packer.pack(*data)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
            end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'types/string'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'types/nil'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'types/false'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'types/true'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'types/integer'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'types/float'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'types/time'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative 'types/color'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative 'types/array'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative 'types/class'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative 'types/type'
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine Array.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0x80; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed type, raw
         
     | 
| 
      
 7 
     | 
    
         
            +
                    length = if type == packer_code 
         
     | 
| 
      
 8 
     | 
    
         
            +
                      Packer.read_packed_bytes(1, from: raw) + 31
         
     | 
| 
      
 9 
     | 
    
         
            +
                    else
         
     | 
| 
      
 10 
     | 
    
         
            +
                      type - packer_code
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
                    
         
     | 
| 
      
 13 
     | 
    
         
            +
                    array = Packer.unpack raw, limit: length
         
     | 
| 
      
 14 
     | 
    
         
            +
                    raise Packer::FormatError, 'Badly formatted array' unless array.length == length
         
     | 
| 
      
 15 
     | 
    
         
            +
                    
         
     | 
| 
      
 16 
     | 
    
         
            +
                    return array
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                refine Array do
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 22 
     | 
    
         
            +
                    header = case length
         
     | 
| 
      
 23 
     | 
    
         
            +
                    when 0 then return nil.to_packed
         
     | 
| 
      
 24 
     | 
    
         
            +
                    when 1..31
         
     | 
| 
      
 25 
     | 
    
         
            +
                      [self.class.packer_code + length].pack(?C)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    when 32..288
         
     | 
| 
      
 27 
     | 
    
         
            +
                      [self.class.packer_code, length - 31].pack('C2')
         
     | 
| 
      
 28 
     | 
    
         
            +
                    else
         
     | 
| 
      
 29 
     | 
    
         
            +
                      raise ArgumentError, 'Array is too long'
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                    
         
     | 
| 
      
 32 
     | 
    
         
            +
                    header + map{|v| v.to_packed }.join
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine FalseClass.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xC2; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed type, _
         
     | 
| 
      
 7 
     | 
    
         
            +
                    type == packer_code ? false : true
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                refine FalseClass do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 13 
     | 
    
         
            +
                    [self.class.packer_code].pack ?C
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine Float.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xC7; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed _, raw
         
     | 
| 
      
 7 
     | 
    
         
            +
                    Packer.read_packed_bytes 4, from: raw, as: 'e'
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                refine Float do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 13 
     | 
    
         
            +
                    [self.class.packer_code, self].pack 'Ce'
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine Integer.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xC4; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed type, raw
         
     | 
| 
      
 7 
     | 
    
         
            +
                    case type
         
     | 
| 
      
 8 
     | 
    
         
            +
                    when 0xC4
         
     | 
| 
      
 9 
     | 
    
         
            +
                      Packer.read_packed_bytes 1, from: raw
         
     | 
| 
      
 10 
     | 
    
         
            +
                    when 0xC5
         
     | 
| 
      
 11 
     | 
    
         
            +
                      Packer.read_packed_bytes 2, from: raw, as: 's<'
         
     | 
| 
      
 12 
     | 
    
         
            +
                    when 0xC6
         
     | 
| 
      
 13 
     | 
    
         
            +
                      Packer.read_packed_bytes 4, from: raw, as: 'l<'  
         
     | 
| 
      
 14 
     | 
    
         
            +
                    when 0..0x7F, 0xD0..0xFF
         
     | 
| 
      
 15 
     | 
    
         
            +
                      [type].pack('C').unpack('c').first
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                refine Integer do
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 22 
     | 
    
         
            +
                    case self
         
     | 
| 
      
 23 
     | 
    
         
            +
                    when -48..127
         
     | 
| 
      
 24 
     | 
    
         
            +
                      [self].pack ?C
         
     | 
| 
      
 25 
     | 
    
         
            +
                    when 0..255
         
     | 
| 
      
 26 
     | 
    
         
            +
                      [self.class.packer_code, self].pack 'C2'
         
     | 
| 
      
 27 
     | 
    
         
            +
                    when -32_768..32_767
         
     | 
| 
      
 28 
     | 
    
         
            +
                      [self.class.packer_code + 1, self].pack 'Cs<'
         
     | 
| 
      
 29 
     | 
    
         
            +
                    when -2_147_483_648..2_147_483_647
         
     | 
| 
      
 30 
     | 
    
         
            +
                      [self.class.packer_code + 2, self].pack 'Cl<'
         
     | 
| 
      
 31 
     | 
    
         
            +
                    else
         
     | 
| 
      
 32 
     | 
    
         
            +
                      raise ArgumentError, 'Integer is larger than 32 bit signed'
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  
         
     | 
| 
      
 36 
     | 
    
         
            +
                  
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine NilClass.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xC1; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed _, _
         
     | 
| 
      
 7 
     | 
    
         
            +
                    return nil
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                refine NilClass do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 13 
     | 
    
         
            +
                    [self.class.packer_code].pack ?C
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine String.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xA0; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed type, raw
         
     | 
| 
      
 7 
     | 
    
         
            +
                    length = if type == packer_code
         
     | 
| 
      
 8 
     | 
    
         
            +
                      Packer.read_packed_bytes(1, from: raw) + 31
         
     | 
| 
      
 9 
     | 
    
         
            +
                    else
         
     | 
| 
      
 10 
     | 
    
         
            +
                      type - packer_code
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
                    Packer.read_packed_bytes length, from: raw, as: 'A*'
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                refine String do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 18 
     | 
    
         
            +
                    case length
         
     | 
| 
      
 19 
     | 
    
         
            +
                    when 0 then return nil.to_packed
         
     | 
| 
      
 20 
     | 
    
         
            +
                    when 1..31
         
     | 
| 
      
 21 
     | 
    
         
            +
                      [self.class.packer_code + length, self].pack('CA*')
         
     | 
| 
      
 22 
     | 
    
         
            +
                    when 32..288
         
     | 
| 
      
 23 
     | 
    
         
            +
                      [self.class.packer_code, length - 31, self].pack('C2A*')
         
     | 
| 
      
 24 
     | 
    
         
            +
                    else
         
     | 
| 
      
 25 
     | 
    
         
            +
                      raise ArgumentError, 'String is too long'
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine Time.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xC8; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed _, raw
         
     | 
| 
      
 7 
     | 
    
         
            +
                    at(Packer.read_packed_bytes 4, from: raw, as: 'L<')
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                refine Time do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 13 
     | 
    
         
            +
                    [self.class.packer_code, to_i].pack 'CL<'
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                refine TrueClass.singleton_class do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def packer_code; 0xC2; end
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def from_packed type, _
         
     | 
| 
      
 7 
     | 
    
         
            +
                    type == packer_code ? false : true
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                refine TrueClass do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 13 
     | 
    
         
            +
                    [self.class.packer_code + 1].pack ?C
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MQTTPipe
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Type
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend self
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def packer_code
         
     | 
| 
      
 7 
     | 
    
         
            +
                    0xC0
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def to_packed
         
     | 
| 
      
 11 
     | 
    
         
            +
                    [packer_code, packer_code].pack 'C2'
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def lookup type
         
     | 
| 
      
 15 
     | 
    
         
            +
                    case type
         
     | 
| 
      
 16 
     | 
    
         
            +
                    when 0x80..0x9F then Array
         
     | 
| 
      
 17 
     | 
    
         
            +
                    when 0xA0..0xBF then String
         
     | 
| 
      
 18 
     | 
    
         
            +
                    when 0xC0       then Type          
         
     | 
| 
      
 19 
     | 
    
         
            +
                    when 0xC1       then NilClass
         
     | 
| 
      
 20 
     | 
    
         
            +
                    when 0xC2       then FalseClass
         
     | 
| 
      
 21 
     | 
    
         
            +
                    when 0xC3       then TrueClass
         
     | 
| 
      
 22 
     | 
    
         
            +
                    when 0xC7       then Float
         
     | 
| 
      
 23 
     | 
    
         
            +
                    when 0xC8       then Time
         
     | 
| 
      
 24 
     | 
    
         
            +
                    when 0xC9       then Color
         
     | 
| 
      
 25 
     | 
    
         
            +
                    when 0x00..0x7F,
         
     | 
| 
      
 26 
     | 
    
         
            +
                         0xD0..0xFF,
         
     | 
| 
      
 27 
     | 
    
         
            +
                         0xC4..0xC6 then Integer
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def from_packed _, raw
         
     | 
| 
      
 32 
     | 
    
         
            +
                    lookup(Packer.read_packed_bytes 1, from: raw)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
    
        data/mqtt_pipe.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'mqtt_pipe/version'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.name          = "mqtt_pipe"
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.version       = MQTTPipe::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.authors       = ["Sebastian Lindberg"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.email         = ["seb.lindberg@gmail.com"]
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary       = %q{A gem for sending a small set of objects via MQTT.}
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description   = %q{This gem wraps the MQTT gem by njh (on Github) and adds a serializer for simple data structures.}
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.homepage      = "https://github.com/seblindberg/ruby-mqtt-pipe"
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.license       = "MIT"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              spec.files         = `git ls-files -z`.split("\x0")
         
     | 
| 
      
 17 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         
     | 
| 
      
 18 
     | 
    
         
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
      
 19 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              spec.add_dependency "mqtt", "~> 0.3"
         
     | 
| 
      
 22 
     | 
    
         
            +
              
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.add_development_dependency "bundler", "~> 1.7"
         
     | 
| 
      
 24 
     | 
    
         
            +
              spec.add_development_dependency "rake", "~> 10.0"
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_development_dependency "rspec", "~> 3.3"
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/config_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'mqtt_pipe'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe MQTTPipe::Config do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:klass) { MQTTPipe::Config }
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              before :each do 
         
     | 
| 
      
 7 
     | 
    
         
            +
                @config = klass.new
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
              describe '#on' do    
         
     | 
| 
      
 11 
     | 
    
         
            +
                it 'requires one argument and a block' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  expect{@config.on}.to raise_error(ArgumentError)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  expect{@config.on 'test'}.to raise_error(ArgumentError)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  expect{@config.on('test') {}}.not_to raise_error
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                it 'stores the listener' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  expect(@config.listeners.length).to eq(0)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @config.on('test') {}
         
     | 
| 
      
 21 
     | 
    
         
            +
                  
         
     | 
| 
      
 22 
     | 
    
         
            +
                  expect(@config.listeners.length).to eq(1)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,87 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'mqtt_pipe'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe MQTTPipe::Listener do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:klass) { MQTTPipe::Listener }
         
     | 
| 
      
 5 
     | 
    
         
            +
              let(:topic)              { 'test/*/topic/#' }
         
     | 
| 
      
 6 
     | 
    
         
            +
              let(:matching_topic_1)   { 'test/some/topic' }
         
     | 
| 
      
 7 
     | 
    
         
            +
              let(:matching_topic_2)   { 'test/some/topic/with/more/5' }
         
     | 
| 
      
 8 
     | 
    
         
            +
              let(:non_matching_topic) { 'test/topic/with/8' }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              describe '#new' do    
         
     | 
| 
      
 11 
     | 
    
         
            +
                it 'expects a topic and an action block' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  expect{klass.new}.to raise_error(ArgumentError)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  expect{klass.new topic}.to raise_error(ArgumentError)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  expect{klass.new(topic) {}}.not_to raise_error
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
              context 'Using the listener' do
         
     | 
| 
      
 19 
     | 
    
         
            +
                before :each do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @listener = klass.new(topic) {|value, captures = 2| value * captures.to_i }
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                describe '#topic' do    
         
     | 
| 
      
 24 
     | 
    
         
            +
                  it 'returns the topic' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                    expect(@listener.topic).to eq topic
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
                describe '#pattern' do    
         
     | 
| 
      
 30 
     | 
    
         
            +
                  it 'returns a regular expression mathing the pattern' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    pattern = @listener.pattern
         
     | 
| 
      
 32 
     | 
    
         
            +
                    
         
     | 
| 
      
 33 
     | 
    
         
            +
                    expect(pattern).to be_a(Regexp)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    expect(pattern === topic).to be true
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  
         
     | 
| 
      
 37 
     | 
    
         
            +
                  it 'leaves lopics without wildcards as is' do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    listener = klass.new('test/of') {}
         
     | 
| 
      
 39 
     | 
    
         
            +
                    expect(listener.pattern === 'test/of').to be_truthy
         
     | 
| 
      
 40 
     | 
    
         
            +
                    expect(listener.pattern).to eq %r{^test/of$}
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                describe '#match' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  it 'requires one argument' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                    expect{@listener.match}.to raise_error ArgumentError
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  
         
     | 
| 
      
 49 
     | 
    
         
            +
                  it 'returns true for a matching topic' do
         
     | 
| 
      
 50 
     | 
    
         
            +
                    expect(@listener.match matching_topic_1).to be_truthy
         
     | 
| 
      
 51 
     | 
    
         
            +
                    expect(@listener.match matching_topic_2).to be_truthy
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  
         
     | 
| 
      
 54 
     | 
    
         
            +
                  it 'returns nil for a non matching topic' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    expect(@listener.match non_matching_topic).to be false
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  
         
     | 
| 
      
 58 
     | 
    
         
            +
                  it 'also responds to #===' do
         
     | 
| 
      
 59 
     | 
    
         
            +
                    expect(@listener === matching_topic_1).to be true
         
     | 
| 
      
 60 
     | 
    
         
            +
                    expect(@listener === non_matching_topic).to be false
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  
         
     | 
| 
      
 63 
     | 
    
         
            +
                  it 'captures wildcard match groups' do
         
     | 
| 
      
 64 
     | 
    
         
            +
                    m = @listener.match matching_topic_2
         
     | 
| 
      
 65 
     | 
    
         
            +
                    
         
     | 
| 
      
 66 
     | 
    
         
            +
                    expect(m).not_to be false
         
     | 
| 
      
 67 
     | 
    
         
            +
                    expect(m[0]).to eq 'some'
         
     | 
| 
      
 68 
     | 
    
         
            +
                    expect(m[1]).to eq 'with/more/5'
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
                
         
     | 
| 
      
 72 
     | 
    
         
            +
                describe '#call' do      
         
     | 
| 
      
 73 
     | 
    
         
            +
                  it 'runs the given callback' do
         
     | 
| 
      
 74 
     | 
    
         
            +
                    expect(@listener.call 42).to eq 84
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  
         
     | 
| 
      
 77 
     | 
    
         
            +
                  it 'accepts an optional second argument' do
         
     | 
| 
      
 78 
     | 
    
         
            +
                    expect(@listener.call 12, 3).to eq 12*3
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  
         
     | 
| 
      
 81 
     | 
    
         
            +
                  it 'also responds to #run' do
         
     | 
| 
      
 82 
     | 
    
         
            +
                    expect(@listener.run 42).to eq 84
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
                
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/packer_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,264 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'mqtt_pipe'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe MQTTPipe::Packer do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:klass) { MQTTPipe::Packer }
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              describe '#pack/#[]' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                describe 'Array' do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  it 'serializes empty arrays to nil' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    expect(klass[[]]).to eq [0xC1].pack('C')
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                  
         
     | 
| 
      
 12 
     | 
    
         
            +
                  it 'serializes short arrays' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                    arr = (0..4).to_a
         
     | 
| 
      
 14 
     | 
    
         
            +
                    expect(klass[arr]).to eq [0x85, 0, 1, 2, 3, 4].pack('C*')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  
         
     | 
| 
      
 17 
     | 
    
         
            +
                  it 'serializes long arrays' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                    arr = (1..100).to_a
         
     | 
| 
      
 19 
     | 
    
         
            +
                    expect(klass[arr].length).to be 102
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                describe 'String' do
         
     | 
| 
      
 24 
     | 
    
         
            +
                  it 'serializes empty strings to nil' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                    expect(klass['']).to eq [0xC1].pack('C')
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  
         
     | 
| 
      
 28 
     | 
    
         
            +
                  it 'serializes short strings' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    expect{klass['string']}.not_to raise_error
         
     | 
| 
      
 30 
     | 
    
         
            +
                    expect(klass['string']).to eq [0xA6, 'string'].pack('CA*')
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  
         
     | 
| 
      
 33 
     | 
    
         
            +
                  it 'serializes long strings' do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    long_string = '*' * 33
         
     | 
| 
      
 35 
     | 
    
         
            +
                    expect(klass[long_string]).to eq [0xA0, long_string.length - 31, long_string].pack('C2A*')
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  
         
     | 
| 
      
 38 
     | 
    
         
            +
                  it 'does not serialize string longer than 288 chars' do
         
     | 
| 
      
 39 
     | 
    
         
            +
                    too_long_string = '*' * 289
         
     | 
| 
      
 40 
     | 
    
         
            +
                    expect{klass[too_long_string]}.to raise_error ArgumentError
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                describe 'Type' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  it 'serializes classes' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                    expect(klass[MQTTPipe::Types::Type]).to eq [0xC0, 0xC0].pack('C2')
         
     | 
| 
      
 47 
     | 
    
         
            +
                    
         
     | 
| 
      
 48 
     | 
    
         
            +
                    expect(klass[NilClass]).to eq [0xC0, 0xC1].pack('C2')
         
     | 
| 
      
 49 
     | 
    
         
            +
                    
         
     | 
| 
      
 50 
     | 
    
         
            +
                    expect(klass[FalseClass]).to eq [0xC0, 0xC2].pack('C2')
         
     | 
| 
      
 51 
     | 
    
         
            +
                    expect(klass[TrueClass]).to eq [0xC0, 0xC2].pack('C2')
         
     | 
| 
      
 52 
     | 
    
         
            +
                    
         
     | 
| 
      
 53 
     | 
    
         
            +
                    expect(klass[Array]).to eq [0xC0, 0x80].pack('C2')
         
     | 
| 
      
 54 
     | 
    
         
            +
                    expect(klass[String]).to eq [0xC0, 0xA0].pack('C2')
         
     | 
| 
      
 55 
     | 
    
         
            +
                    
         
     | 
| 
      
 56 
     | 
    
         
            +
                    expect(klass[Fixnum]).to eq [0xC0, 0xC4].pack('C2')
         
     | 
| 
      
 57 
     | 
    
         
            +
                    expect(klass[Integer]).to eq [0xC0, 0xC4].pack('C2')
         
     | 
| 
      
 58 
     | 
    
         
            +
                    
         
     | 
| 
      
 59 
     | 
    
         
            +
                    expect(klass[Float]).to eq [0xC0, 0xC7].pack('C2')
         
     | 
| 
      
 60 
     | 
    
         
            +
                    expect(klass[Time]).to eq [0xC0, 0xC8].pack('C2')
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                
         
     | 
| 
      
 64 
     | 
    
         
            +
                describe 'Nil' do
         
     | 
| 
      
 65 
     | 
    
         
            +
                  it 'serializes nil values' do
         
     | 
| 
      
 66 
     | 
    
         
            +
                    expect(klass[nil]).to eq [0xC1].pack(?C)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                describe 'Boolean' do
         
     | 
| 
      
 71 
     | 
    
         
            +
                  it 'serializes false values' do
         
     | 
| 
      
 72 
     | 
    
         
            +
                    expect(klass[false]).to eq [0xC2].pack(?C)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                  
         
     | 
| 
      
 75 
     | 
    
         
            +
                  it 'serializes true values' do
         
     | 
| 
      
 76 
     | 
    
         
            +
                    expect(klass[true]).to eq [0xC3].pack(?C)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
                
         
     | 
| 
      
 80 
     | 
    
         
            +
                describe 'Integer' do
         
     | 
| 
      
 81 
     | 
    
         
            +
                  it 'serializes small integers' do
         
     | 
| 
      
 82 
     | 
    
         
            +
                    expect(klass[4]).to eq [4].pack(?c)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    expect(klass[127]).to eq [127].pack(?c)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    expect(klass[-48]).to eq [-48].pack(?c)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                  
         
     | 
| 
      
 87 
     | 
    
         
            +
                  it 'serializes bytes' do
         
     | 
| 
      
 88 
     | 
    
         
            +
                    expect(klass[128]).to eq [0xC4, 128].pack('C2')
         
     | 
| 
      
 89 
     | 
    
         
            +
                    expect(klass[255]).to eq [0xC4, 255].pack('C2')
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
                  
         
     | 
| 
      
 92 
     | 
    
         
            +
                  it 'serializes short integers' do
         
     | 
| 
      
 93 
     | 
    
         
            +
                    expect(klass[32_767]).to eq [0xC5, 32_767].pack('Cs<')
         
     | 
| 
      
 94 
     | 
    
         
            +
                    expect(klass[-32_768]).to eq [0xC5, -32_768].pack('Cs<')
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  
         
     | 
| 
      
 97 
     | 
    
         
            +
                  it 'serializes integers' do
         
     | 
| 
      
 98 
     | 
    
         
            +
                    expect(klass[2_147_483_647]).to eq [0xC6, 2_147_483_647].pack('Cl<')
         
     | 
| 
      
 99 
     | 
    
         
            +
                    expect(klass[-2_147_483_648]).to eq [0xC6, -2_147_483_648].pack('Cl<')
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  
         
     | 
| 
      
 102 
     | 
    
         
            +
                  it 'does not serialize integers larger than 32 bit' do
         
     | 
| 
      
 103 
     | 
    
         
            +
                    expect{klass[2_147_483_648]}.to raise_error ArgumentError
         
     | 
| 
      
 104 
     | 
    
         
            +
                    expect{klass[-2_147_483_649]}.to raise_error ArgumentError
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
                
         
     | 
| 
      
 108 
     | 
    
         
            +
                describe 'Float' do
         
     | 
| 
      
 109 
     | 
    
         
            +
                  it 'serializes 32 bit floats' do
         
     | 
| 
      
 110 
     | 
    
         
            +
                    expect(klass[0.2]).to eq [0xC7, 0.2].pack('Ce')
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
                
         
     | 
| 
      
 114 
     | 
    
         
            +
                describe 'Time' do
         
     | 
| 
      
 115 
     | 
    
         
            +
                  it 'serializes time' do
         
     | 
| 
      
 116 
     | 
    
         
            +
                    timestamp = Time.now
         
     | 
| 
      
 117 
     | 
    
         
            +
                    expect(klass[timestamp]).to eq [0xC8, timestamp.to_i].pack('CL<')
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
              
         
     | 
| 
      
 122 
     | 
    
         
            +
              
         
     | 
| 
      
 123 
     | 
    
         
            +
              describe '#unpack' do
         
     | 
| 
      
 124 
     | 
    
         
            +
                it 'raises an error on malformated packets' do
         
     | 
| 
      
 125 
     | 
    
         
            +
                  # Make the list one item longer than what is written
         
     | 
| 
      
 126 
     | 
    
         
            +
                  raw = [0x87, *(1..6).to_a].pack 'CC*'
         
     | 
| 
      
 127 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 128 
     | 
    
         
            +
                  
         
     | 
| 
      
 129 
     | 
    
         
            +
                  # Strings
         
     | 
| 
      
 130 
     | 
    
         
            +
                  raw = [0xA7, 'string'].pack 'CA*'
         
     | 
| 
      
 131 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 132 
     | 
    
         
            +
                  
         
     | 
| 
      
 133 
     | 
    
         
            +
                  # Integers
         
     | 
| 
      
 134 
     | 
    
         
            +
                  raw = [0xC4].pack 'C'
         
     | 
| 
      
 135 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 136 
     | 
    
         
            +
                  
         
     | 
| 
      
 137 
     | 
    
         
            +
                  raw = [0xC5, 1].pack 'C*'
         
     | 
| 
      
 138 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 139 
     | 
    
         
            +
                  
         
     | 
| 
      
 140 
     | 
    
         
            +
                  raw = [0xC6, 1,2,3].pack 'C*'
         
     | 
| 
      
 141 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 142 
     | 
    
         
            +
                  
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # Float
         
     | 
| 
      
 144 
     | 
    
         
            +
                  raw = [0xC7].pack 'C*'
         
     | 
| 
      
 145 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 146 
     | 
    
         
            +
                  
         
     | 
| 
      
 147 
     | 
    
         
            +
                  # Time
         
     | 
| 
      
 148 
     | 
    
         
            +
                  raw = [0xC8, 1].pack 'C*'
         
     | 
| 
      
 149 
     | 
    
         
            +
                  expect{klass.unpack(raw)}.to raise_error MQTTPipe::Packer::FormatError
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
                
         
     | 
| 
      
 152 
     | 
    
         
            +
                describe 'Array' do
         
     | 
| 
      
 153 
     | 
    
         
            +
                  it 'deserializes short arrays' do
         
     | 
| 
      
 154 
     | 
    
         
            +
                    raw = [0x86, *(1..6).to_a].pack 'CC6'
         
     | 
| 
      
 155 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq (1..6).to_a
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
                
         
     | 
| 
      
 159 
     | 
    
         
            +
                describe 'String' do      
         
     | 
| 
      
 160 
     | 
    
         
            +
                  it 'deserializes short strings' do
         
     | 
| 
      
 161 
     | 
    
         
            +
                    raw = [0xA6, 'string'].pack 'CA*'
         
     | 
| 
      
 162 
     | 
    
         
            +
                    
         
     | 
| 
      
 163 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq 'string'
         
     | 
| 
      
 164 
     | 
    
         
            +
                  end
         
     | 
| 
      
 165 
     | 
    
         
            +
                  
         
     | 
| 
      
 166 
     | 
    
         
            +
                  it 'deserializes long strings' do
         
     | 
| 
      
 167 
     | 
    
         
            +
                    long_string = '*' * 33
         
     | 
| 
      
 168 
     | 
    
         
            +
                    raw = [0xA0, long_string.length - 31, long_string].pack 'C2A*'
         
     | 
| 
      
 169 
     | 
    
         
            +
                    
         
     | 
| 
      
 170 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq long_string
         
     | 
| 
      
 171 
     | 
    
         
            +
                  end
         
     | 
| 
      
 172 
     | 
    
         
            +
                end
         
     | 
| 
      
 173 
     | 
    
         
            +
                
         
     | 
| 
      
 174 
     | 
    
         
            +
                describe 'Type' do
         
     | 
| 
      
 175 
     | 
    
         
            +
                  it 'deserializes types' do
         
     | 
| 
      
 176 
     | 
    
         
            +
                    raw = [0xC0, 0xC0].pack 'C2'
         
     | 
| 
      
 177 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to be MQTTPipe::Types::Type
         
     | 
| 
      
 178 
     | 
    
         
            +
                  end
         
     | 
| 
      
 179 
     | 
    
         
            +
                end
         
     | 
| 
      
 180 
     | 
    
         
            +
                
         
     | 
| 
      
 181 
     | 
    
         
            +
                describe 'Nil' do      
         
     | 
| 
      
 182 
     | 
    
         
            +
                  it 'deserializes nil' do
         
     | 
| 
      
 183 
     | 
    
         
            +
                    raw = [0xC1].pack 'C'
         
     | 
| 
      
 184 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to be nil
         
     | 
| 
      
 185 
     | 
    
         
            +
                  end
         
     | 
| 
      
 186 
     | 
    
         
            +
                end
         
     | 
| 
      
 187 
     | 
    
         
            +
                
         
     | 
| 
      
 188 
     | 
    
         
            +
                describe 'Boolean' do      
         
     | 
| 
      
 189 
     | 
    
         
            +
                  it 'deserializes to false' do
         
     | 
| 
      
 190 
     | 
    
         
            +
                    raw = [0xC2].pack 'C'
         
     | 
| 
      
 191 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to be false
         
     | 
| 
      
 192 
     | 
    
         
            +
                  end
         
     | 
| 
      
 193 
     | 
    
         
            +
                  
         
     | 
| 
      
 194 
     | 
    
         
            +
                  it 'deserializes to true' do
         
     | 
| 
      
 195 
     | 
    
         
            +
                    raw = [0xC3].pack 'C'
         
     | 
| 
      
 196 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to be true
         
     | 
| 
      
 197 
     | 
    
         
            +
                  end
         
     | 
| 
      
 198 
     | 
    
         
            +
                end
         
     | 
| 
      
 199 
     | 
    
         
            +
                
         
     | 
| 
      
 200 
     | 
    
         
            +
                describe 'Integer' do
         
     | 
| 
      
 201 
     | 
    
         
            +
                  it 'deserializes tiny integers' do
         
     | 
| 
      
 202 
     | 
    
         
            +
                    raw = [127].pack ?C
         
     | 
| 
      
 203 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq 127
         
     | 
| 
      
 204 
     | 
    
         
            +
                    
         
     | 
| 
      
 205 
     | 
    
         
            +
                    raw = [-48].pack ?C
         
     | 
| 
      
 206 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq -48
         
     | 
| 
      
 207 
     | 
    
         
            +
                  end
         
     | 
| 
      
 208 
     | 
    
         
            +
                  
         
     | 
| 
      
 209 
     | 
    
         
            +
                  it 'deserializes bytes' do
         
     | 
| 
      
 210 
     | 
    
         
            +
                    raw = [0xC4, 128].pack 'C2'
         
     | 
| 
      
 211 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq 128
         
     | 
| 
      
 212 
     | 
    
         
            +
                  end
         
     | 
| 
      
 213 
     | 
    
         
            +
                  
         
     | 
| 
      
 214 
     | 
    
         
            +
                  it 'deserializes short integers' do
         
     | 
| 
      
 215 
     | 
    
         
            +
                    raw = [0xC5, 32_767].pack 'Cs<'
         
     | 
| 
      
 216 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq 32_767
         
     | 
| 
      
 217 
     | 
    
         
            +
                    
         
     | 
| 
      
 218 
     | 
    
         
            +
                    raw = [0xC5, -32_768].pack 'Cs<'
         
     | 
| 
      
 219 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq -32_768
         
     | 
| 
      
 220 
     | 
    
         
            +
                  end
         
     | 
| 
      
 221 
     | 
    
         
            +
                  
         
     | 
| 
      
 222 
     | 
    
         
            +
                  it 'deserializes long integers' do
         
     | 
| 
      
 223 
     | 
    
         
            +
                    raw = [0xC6, 2_147_483_647].pack 'Cl<'
         
     | 
| 
      
 224 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq 2_147_483_647
         
     | 
| 
      
 225 
     | 
    
         
            +
                    
         
     | 
| 
      
 226 
     | 
    
         
            +
                    raw = [0xC6, -2_147_483_648].pack 'Cl<'
         
     | 
| 
      
 227 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to eq -2_147_483_648
         
     | 
| 
      
 228 
     | 
    
         
            +
                  end
         
     | 
| 
      
 229 
     | 
    
         
            +
                end
         
     | 
| 
      
 230 
     | 
    
         
            +
                
         
     | 
| 
      
 231 
     | 
    
         
            +
                describe 'Float' do      
         
     | 
| 
      
 232 
     | 
    
         
            +
                  it 'deserializes float' do
         
     | 
| 
      
 233 
     | 
    
         
            +
                    raw = [0xC7, 0.4].pack 'Ce'
         
     | 
| 
      
 234 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to be_within(0.0001).of(0.4)
         
     | 
| 
      
 235 
     | 
    
         
            +
                  end
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
      
 237 
     | 
    
         
            +
                
         
     | 
| 
      
 238 
     | 
    
         
            +
                describe 'Time' do
         
     | 
| 
      
 239 
     | 
    
         
            +
                  it 'deserializes time' do
         
     | 
| 
      
 240 
     | 
    
         
            +
                    t = Time.now
         
     | 
| 
      
 241 
     | 
    
         
            +
                    raw = [0xC8, t.to_i].pack 'CL<'
         
     | 
| 
      
 242 
     | 
    
         
            +
                    expect(klass.unpack(raw).first).to be_a Time
         
     | 
| 
      
 243 
     | 
    
         
            +
                    expect(klass.unpack(raw).first - t).to be_within(1).of(0)
         
     | 
| 
      
 244 
     | 
    
         
            +
                  end
         
     | 
| 
      
 245 
     | 
    
         
            +
                end
         
     | 
| 
      
 246 
     | 
    
         
            +
              end
         
     | 
| 
      
 247 
     | 
    
         
            +
              
         
     | 
| 
      
 248 
     | 
    
         
            +
              describe 'End to end' do
         
     | 
| 
      
 249 
     | 
    
         
            +
                it 'can serialize and deserialize an object' do
         
     | 
| 
      
 250 
     | 
    
         
            +
                  packet = ['Hello there!', 42, 42_531, ['hi', Time], true, []]
         
     | 
| 
      
 251 
     | 
    
         
            +
                  
         
     | 
| 
      
 252 
     | 
    
         
            +
                  req = klass.pack *packet
         
     | 
| 
      
 253 
     | 
    
         
            +
                  res = klass.unpack req
         
     | 
| 
      
 254 
     | 
    
         
            +
                        
         
     | 
| 
      
 255 
     | 
    
         
            +
                  expect(res[0]).to eq 'Hello there!'
         
     | 
| 
      
 256 
     | 
    
         
            +
                  expect(res[1]).to eq 42
         
     | 
| 
      
 257 
     | 
    
         
            +
                  expect(res[2]).to eq 42_531
         
     | 
| 
      
 258 
     | 
    
         
            +
                  expect(res[3][0]).to eq 'hi'
         
     | 
| 
      
 259 
     | 
    
         
            +
                  expect(res[3][1]).to eq Time
         
     | 
| 
      
 260 
     | 
    
         
            +
                  expect(res[4]).to eq true
         
     | 
| 
      
 261 
     | 
    
         
            +
                  expect(res[5]).to eq nil
         
     | 
| 
      
 262 
     | 
    
         
            +
                end
         
     | 
| 
      
 263 
     | 
    
         
            +
              end
         
     | 
| 
      
 264 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/pipe_spec.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,135 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: mqtt_pipe
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Sebastian Lindberg
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-08-26 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: mqtt
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '0.3'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '0.3'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '1.7'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '1.7'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '10.0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '10.0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '3.3'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '3.3'
         
     | 
| 
      
 69 
     | 
    
         
            +
            description: This gem wraps the MQTT gem by njh (on Github) and adds a serializer
         
     | 
| 
      
 70 
     | 
    
         
            +
              for simple data structures.
         
     | 
| 
      
 71 
     | 
    
         
            +
            email:
         
     | 
| 
      
 72 
     | 
    
         
            +
            - seb.lindberg@gmail.com
         
     | 
| 
      
 73 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 74 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 75 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 76 
     | 
    
         
            +
            files:
         
     | 
| 
      
 77 
     | 
    
         
            +
            - ".gitignore"
         
     | 
| 
      
 78 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 79 
     | 
    
         
            +
            - LICENSE.txt
         
     | 
| 
      
 80 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 81 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 82 
     | 
    
         
            +
            - examples/receiver.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - examples/sender.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - lib/mqtt_pipe.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - lib/mqtt_pipe/config.rb
         
     | 
| 
      
 86 
     | 
    
         
            +
            - lib/mqtt_pipe/listener.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            - lib/mqtt_pipe/packer.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/mqtt_pipe/pipe.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - lib/mqtt_pipe/types.rb
         
     | 
| 
      
 90 
     | 
    
         
            +
            - lib/mqtt_pipe/types/array.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - lib/mqtt_pipe/types/class.rb
         
     | 
| 
      
 92 
     | 
    
         
            +
            - lib/mqtt_pipe/types/color.rb
         
     | 
| 
      
 93 
     | 
    
         
            +
            - lib/mqtt_pipe/types/false.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - lib/mqtt_pipe/types/float.rb
         
     | 
| 
      
 95 
     | 
    
         
            +
            - lib/mqtt_pipe/types/integer.rb
         
     | 
| 
      
 96 
     | 
    
         
            +
            - lib/mqtt_pipe/types/nil.rb
         
     | 
| 
      
 97 
     | 
    
         
            +
            - lib/mqtt_pipe/types/string.rb
         
     | 
| 
      
 98 
     | 
    
         
            +
            - lib/mqtt_pipe/types/time.rb
         
     | 
| 
      
 99 
     | 
    
         
            +
            - lib/mqtt_pipe/types/true.rb
         
     | 
| 
      
 100 
     | 
    
         
            +
            - lib/mqtt_pipe/types/type.rb
         
     | 
| 
      
 101 
     | 
    
         
            +
            - lib/mqtt_pipe/version.rb
         
     | 
| 
      
 102 
     | 
    
         
            +
            - mqtt_pipe.gemspec
         
     | 
| 
      
 103 
     | 
    
         
            +
            - spec/config_spec.rb
         
     | 
| 
      
 104 
     | 
    
         
            +
            - spec/listener_spec.rb
         
     | 
| 
      
 105 
     | 
    
         
            +
            - spec/packer_spec.rb
         
     | 
| 
      
 106 
     | 
    
         
            +
            - spec/pipe_spec.rb
         
     | 
| 
      
 107 
     | 
    
         
            +
            homepage: https://github.com/seblindberg/ruby-mqtt-pipe
         
     | 
| 
      
 108 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 109 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 110 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 111 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 112 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 113 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 114 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 115 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 116 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 117 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 118 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 119 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 120 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 121 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 122 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 123 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 124 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 125 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 126 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 127 
     | 
    
         
            +
            rubygems_version: 2.4.5
         
     | 
| 
      
 128 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 129 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 130 
     | 
    
         
            +
            summary: A gem for sending a small set of objects via MQTT.
         
     | 
| 
      
 131 
     | 
    
         
            +
            test_files:
         
     | 
| 
      
 132 
     | 
    
         
            +
            - spec/config_spec.rb
         
     | 
| 
      
 133 
     | 
    
         
            +
            - spec/listener_spec.rb
         
     | 
| 
      
 134 
     | 
    
         
            +
            - spec/packer_spec.rb
         
     | 
| 
      
 135 
     | 
    
         
            +
            - spec/pipe_spec.rb
         
     |