lifx-lan 0.1.0
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 +17 -0
 - data/.travis.yml +8 -0
 - data/.yardopts +3 -0
 - data/CHANGES.md +45 -0
 - data/Gemfile +19 -0
 - data/LICENSE.txt +23 -0
 - data/README.md +15 -0
 - data/Rakefile +20 -0
 - data/bin/lifx-snoop +50 -0
 - data/examples/auto-off/auto-off.rb +34 -0
 - data/examples/blink/blink.rb +19 -0
 - data/examples/identify/identify.rb +69 -0
 - data/examples/travis-build-light/build-light.rb +57 -0
 - data/lib/bindata_ext/bool.rb +30 -0
 - data/lib/bindata_ext/record.rb +11 -0
 - data/lib/lifx-lan.rb +27 -0
 - data/lib/lifx/lan/client.rb +149 -0
 - data/lib/lifx/lan/color.rb +199 -0
 - data/lib/lifx/lan/config.rb +17 -0
 - data/lib/lifx/lan/firmware.rb +60 -0
 - data/lib/lifx/lan/gateway_connection.rb +185 -0
 - data/lib/lifx/lan/light.rb +440 -0
 - data/lib/lifx/lan/light_collection.rb +111 -0
 - data/lib/lifx/lan/light_target.rb +185 -0
 - data/lib/lifx/lan/logging.rb +14 -0
 - data/lib/lifx/lan/message.rb +168 -0
 - data/lib/lifx/lan/network_context.rb +188 -0
 - data/lib/lifx/lan/observable.rb +66 -0
 - data/lib/lifx/lan/protocol/address.rb +25 -0
 - data/lib/lifx/lan/protocol/device.rb +387 -0
 - data/lib/lifx/lan/protocol/header.rb +24 -0
 - data/lib/lifx/lan/protocol/light.rb +142 -0
 - data/lib/lifx/lan/protocol/message.rb +19 -0
 - data/lib/lifx/lan/protocol/metadata.rb +23 -0
 - data/lib/lifx/lan/protocol/payload.rb +12 -0
 - data/lib/lifx/lan/protocol/sensor.rb +31 -0
 - data/lib/lifx/lan/protocol/type.rb +204 -0
 - data/lib/lifx/lan/protocol/wan.rb +51 -0
 - data/lib/lifx/lan/protocol/wifi.rb +102 -0
 - data/lib/lifx/lan/protocol_path.rb +85 -0
 - data/lib/lifx/lan/required_keyword_arguments.rb +12 -0
 - data/lib/lifx/lan/routing_manager.rb +114 -0
 - data/lib/lifx/lan/routing_table.rb +48 -0
 - data/lib/lifx/lan/seen.rb +25 -0
 - data/lib/lifx/lan/site.rb +97 -0
 - data/lib/lifx/lan/tag_manager.rb +111 -0
 - data/lib/lifx/lan/tag_table.rb +49 -0
 - data/lib/lifx/lan/target.rb +24 -0
 - data/lib/lifx/lan/thread.rb +13 -0
 - data/lib/lifx/lan/timers.rb +29 -0
 - data/lib/lifx/lan/transport.rb +46 -0
 - data/lib/lifx/lan/transport/tcp.rb +91 -0
 - data/lib/lifx/lan/transport/udp.rb +87 -0
 - data/lib/lifx/lan/transport_manager.rb +43 -0
 - data/lib/lifx/lan/transport_manager/lan.rb +169 -0
 - data/lib/lifx/lan/utilities.rb +36 -0
 - data/lib/lifx/lan/version.rb +5 -0
 - data/lifx-lan.gemspec +26 -0
 - data/spec/color_spec.rb +43 -0
 - data/spec/gateway_connection_spec.rb +30 -0
 - data/spec/integration/client_spec.rb +42 -0
 - data/spec/integration/light_spec.rb +56 -0
 - data/spec/integration/tags_spec.rb +42 -0
 - data/spec/light_collection_spec.rb +37 -0
 - data/spec/message_spec.rb +183 -0
 - data/spec/protocol_path_spec.rb +109 -0
 - data/spec/routing_manager_spec.rb +25 -0
 - data/spec/routing_table_spec.rb +23 -0
 - data/spec/spec_helper.rb +56 -0
 - data/spec/transport/udp_spec.rb +44 -0
 - data/spec/transport_spec.rb +14 -0
 - metadata +187 -0
 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module LIFX
         
     | 
| 
      
 4 
     | 
    
         
            +
              module LAN
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe 'tags', integration: true do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  let(:color) { Color.hsb(rand(360), 0.3, 0.3) }
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  specify 'Clearing, setting and using tags' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    light.add_tag('Foo')
         
     | 
| 
      
 10 
     | 
    
         
            +
                    expect(light.tags).to include('Foo')
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    test_tag = lights.with_tag('Foo')
         
     | 
| 
      
 13 
     | 
    
         
            +
                    test_tag.turn_on
         
     | 
| 
      
 14 
     | 
    
         
            +
                    test_tag.set_color(color, duration: 0)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    flush
         
     | 
| 
      
 16 
     | 
    
         
            +
                    sleep 1 # Set messages are scheduled 250ms if no at_time is set
         
     | 
| 
      
 17 
     | 
    
         
            +
                            # It also returns the current light state rather than the
         
     | 
| 
      
 18 
     | 
    
         
            +
                            # final state
         
     | 
| 
      
 19 
     | 
    
         
            +
                    light.refresh
         
     | 
| 
      
 20 
     | 
    
         
            +
                    wait { expect(light.color).to be_similar_to(color) }
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    light.remove_tag('Foo')
         
     | 
| 
      
 23 
     | 
    
         
            +
                    wait { expect(light.tags).not_to include('Foo') }
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  it 'deletes tags when no longer assigned to a light' do
         
     | 
| 
      
 27 
     | 
    
         
            +
                    light.add_tag('TempTag')
         
     | 
| 
      
 28 
     | 
    
         
            +
                    light.remove_tag('TempTag')
         
     | 
| 
      
 29 
     | 
    
         
            +
                    expect(lifx.unused_tags).to include('TempTag')
         
     | 
| 
      
 30 
     | 
    
         
            +
                    lifx.purge_unused_tags!
         
     | 
| 
      
 31 
     | 
    
         
            +
                    expect(lifx.unused_tags).to be_empty
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  it 'handles non-ascii tags' do
         
     | 
| 
      
 35 
     | 
    
         
            +
                    light.add_tag('_tést')
         
     | 
| 
      
 36 
     | 
    
         
            +
                    expect(light.tags).to include('_tést')
         
     | 
| 
      
 37 
     | 
    
         
            +
                    light.remove_tag('_tést')
         
     | 
| 
      
 38 
     | 
    
         
            +
                    lifx.purge_unused_tags!
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module LIFX
         
     | 
| 
      
 4 
     | 
    
         
            +
              module LAN
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe LightCollection do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  subject(:collection) { LightCollection.new(context: double) }
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  describe '#with_id' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    let(:light) { double(Light, id: 'id') }
         
     | 
| 
      
 10 
     | 
    
         
            +
                    before { allow(collection).to receive(:lights).and_return([light]) }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    it 'returns a Light with matching id' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                      expect(collection.with_id('id')).to eq light
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    it 'returns nil when none matches' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                      ret = collection.with_id('wrong id')
         
     | 
| 
      
 18 
     | 
    
         
            +
                      expect(ret).to eq nil
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  describe '#with_label' do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    let(:light) { double(Light, label: 'label') }
         
     | 
| 
      
 24 
     | 
    
         
            +
                    before { allow(collection).to receive(:lights).and_return([light]) }
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    it 'returns a Light with matching label' do
         
     | 
| 
      
 27 
     | 
    
         
            +
                      expect(collection.with_label('label')).to eq light
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    it 'returns nil' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                      ret = collection.with_label('wrong label')
         
     | 
| 
      
 32 
     | 
    
         
            +
                      expect(ret).to eq nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,183 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe LIFX::LAN::Message do
         
     | 
| 
      
 4 
     | 
    
         
            +
              context 'unpacking' do
         
     | 
| 
      
 5 
     | 
    
         
            +
                let(:data) do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  "\x39\x00\x00\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31" \
         
     | 
| 
      
 7 
     | 
    
         
            +
                  "\x6c\x69\x66\x78\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x67\x00" \
         
     | 
| 
      
 8 
     | 
    
         
            +
                  "\x00\x00\x00\x01\x00\x00\xff\xff\xff\xff\xac\x0d\xc8\x00\x00\x00\x00" \
         
     | 
| 
      
 9 
     | 
    
         
            +
                  "\x00\x80\x3f\x00\x00\x00".b
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                let(:msg) { LIFX::LAN::Message.unpack(data) }
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                it 'unpacks without errors' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  expect(msg).not_to be_nil
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                it 'returns the correct frame data' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  expect(msg.msg_size).to eq 57
         
     | 
| 
      
 19 
     | 
    
         
            +
                  expect(msg.protocol).to eq 1024
         
     | 
| 
      
 20 
     | 
    
         
            +
                  expect(msg).to be_addressable
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                it 'returns the correct address data' do
         
     | 
| 
      
 24 
     | 
    
         
            +
                  expect(msg.raw_site).to eq '1lifx1'
         
     | 
| 
      
 25 
     | 
    
         
            +
                  expect(msg.raw_target).to eq "\x00" * 8
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                it 'has correct ProtocolPath data' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  expect(msg.path).to be_a(LIFX::LAN::ProtocolPath)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  expect(msg.path.site_id).to eq '316c69667831'
         
     | 
| 
      
 31 
     | 
    
         
            +
                  expect(msg.path.tag_ids).to eq []
         
     | 
| 
      
 32 
     | 
    
         
            +
                  expect(msg.path.device_id).to be_nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                it 'returns the correct metadata' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                  expect(msg.at_time).to eq 0
         
     | 
| 
      
 37 
     | 
    
         
            +
                  expect(msg.type_).to eq 103
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                let(:payload) { msg.payload }
         
     | 
| 
      
 41 
     | 
    
         
            +
                it 'returns the payload' do
         
     | 
| 
      
 42 
     | 
    
         
            +
                  expect(payload.class).to eq LIFX::LAN::Protocol::Light::SetWaveform
         
     | 
| 
      
 43 
     | 
    
         
            +
                  expect(payload.stream).to eq 0
         
     | 
| 
      
 44 
     | 
    
         
            +
                  expect(payload.transient).to eq(true)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  expect(payload.color.hue).to eq 0
         
     | 
| 
      
 46 
     | 
    
         
            +
                  expect(payload.color.saturation).to eq 65_535
         
     | 
| 
      
 47 
     | 
    
         
            +
                  expect(payload.color.brightness).to eq 65_535
         
     | 
| 
      
 48 
     | 
    
         
            +
                  expect(payload.color.kelvin).to eq 3_500
         
     | 
| 
      
 49 
     | 
    
         
            +
                  expect(payload.period).to eq 200
         
     | 
| 
      
 50 
     | 
    
         
            +
                  expect(payload.cycles).to eq 1.0
         
     | 
| 
      
 51 
     | 
    
         
            +
                  expect(payload.skew_ratio).to eq 0
         
     | 
| 
      
 52 
     | 
    
         
            +
                  expect(payload.waveform).to eq 0
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                it 'repacks to the same data' do
         
     | 
| 
      
 56 
     | 
    
         
            +
                  expect(msg.pack).to eq data
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              context 'packing' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                context 'no attributes' do
         
     | 
| 
      
 62 
     | 
    
         
            +
                  let(:msg) { LIFX::LAN::Message.new }
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  it 'throws an exception' do
         
     | 
| 
      
 65 
     | 
    
         
            +
                    expect { msg.pack }.to raise_error(LIFX::LAN::Message::NoPayload)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                context 'no path' do
         
     | 
| 
      
 70 
     | 
    
         
            +
                  let(:msg) { LIFX::LAN::Message.new(payload: LIFX::LAN::Protocol::Device::SetPower.new) }
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  it 'defaults to null site and target' do
         
     | 
| 
      
 73 
     | 
    
         
            +
                    unpacked = LIFX::LAN::Message.unpack(msg.pack)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    expect(unpacked.path.site_id).to eq('000000000000')
         
     | 
| 
      
 75 
     | 
    
         
            +
                    expect(unpacked.path.device_id).to eq('000000000000')
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                context 'passed in via hash' do
         
     | 
| 
      
 80 
     | 
    
         
            +
                  let(:msg) do
         
     | 
| 
      
 81 
     | 
    
         
            +
                    LIFX::LAN::Message.new({
         
     | 
| 
      
 82 
     | 
    
         
            +
                      path: LIFX::LAN::ProtocolPath.new(tagged: false, raw_target: 'abcdefgh'),
         
     | 
| 
      
 83 
     | 
    
         
            +
                      at_time: 9001,
         
     | 
| 
      
 84 
     | 
    
         
            +
                      payload: LIFX::LAN::Protocol::Wifi::SetAccessPoint.new(
         
     | 
| 
      
 85 
     | 
    
         
            +
                        interface: 1,
         
     | 
| 
      
 86 
     | 
    
         
            +
                        ssid: 'who let the dogs out',
         
     | 
| 
      
 87 
     | 
    
         
            +
                        pass: 'woof, woof, woof woof!',
         
     | 
| 
      
 88 
     | 
    
         
            +
                        security: 1
         
     | 
| 
      
 89 
     | 
    
         
            +
                      )
         
     | 
| 
      
 90 
     | 
    
         
            +
                    })
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # let(:unpacked) { LIFX::Message.unpack(msg.pack) }
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  it 'sets the size' do
         
     | 
| 
      
 95 
     | 
    
         
            +
                    expect(msg.msg_size).to eq 134
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  it 'packs correctly' do
         
     | 
| 
      
 99 
     | 
    
         
            +
                    expect(msg.pack).to eq "\x86\x00\x00\x14\x00\x00\x00\x00abcdefgh\x00" \
         
     | 
| 
      
 100 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00)#\x00\x00\x00"   \
         
     | 
| 
      
 101 
     | 
    
         
            +
                                           "\x00\x00\x001\x01\x00\x00\x01who let the "    \
         
     | 
| 
      
 102 
     | 
    
         
            +
                                           "dogs out\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
         
     | 
| 
      
 103 
     | 
    
         
            +
                                           "\x00\x00\x00woof, woof, woof woof!\x00\x00"   \
         
     | 
| 
      
 104 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
         
     | 
| 
      
 105 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
         
     | 
| 
      
 106 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
         
     | 
| 
      
 107 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00\x01".b
         
     | 
| 
      
 108 
     | 
    
         
            +
                    expect(msg.protocol).to eq 1024
         
     | 
| 
      
 109 
     | 
    
         
            +
                    expect(msg.path).not_to be_tagged
         
     | 
| 
      
 110 
     | 
    
         
            +
                    expect(msg).to be_addressable
         
     | 
| 
      
 111 
     | 
    
         
            +
                    expect(msg.path.raw_target).to eq 'abcdefgh'
         
     | 
| 
      
 112 
     | 
    
         
            +
                    expect(msg.at_time).to eq 9001
         
     | 
| 
      
 113 
     | 
    
         
            +
                    expect(msg.type_).to eq 305
         
     | 
| 
      
 114 
     | 
    
         
            +
                    expect(msg.payload.class).to eq LIFX::LAN::Protocol::Wifi::SetAccessPoint
         
     | 
| 
      
 115 
     | 
    
         
            +
                    expect(msg.payload.interface).to eq 1
         
     | 
| 
      
 116 
     | 
    
         
            +
                    expect(msg.payload.ssid).to eq 'who let the dogs out'
         
     | 
| 
      
 117 
     | 
    
         
            +
                    expect(msg.payload.pass).to eq 'woof, woof, woof woof!'
         
     | 
| 
      
 118 
     | 
    
         
            +
                    expect(msg.payload.security).to eq 1
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                context 'packing with tags' do
         
     | 
| 
      
 123 
     | 
    
         
            +
                  let(:msg) do
         
     | 
| 
      
 124 
     | 
    
         
            +
                    LIFX::LAN::Message.new({
         
     | 
| 
      
 125 
     | 
    
         
            +
                      path: LIFX::LAN::ProtocolPath.new(tag_ids: [0, 1]),
         
     | 
| 
      
 126 
     | 
    
         
            +
                      at_time: 9001,
         
     | 
| 
      
 127 
     | 
    
         
            +
                      payload: LIFX::LAN::Protocol::Device::GetTime.new
         
     | 
| 
      
 128 
     | 
    
         
            +
                    })
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  let(:unpacked) { LIFX::LAN::Message.unpack(msg.pack) }
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  it 'packs the tag correctly' do
         
     | 
| 
      
 134 
     | 
    
         
            +
                    expect(msg.pack).to eq "$\x00\x004\x00\x00\x00\x00\x03\x00\x00\x00"   \
         
     | 
| 
      
 135 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
         
     | 
| 
      
 136 
     | 
    
         
            +
                                           "\x00)#\x00\x00\x00\x00\x00\x00\x04\x00\x00"   \
         
     | 
| 
      
 137 
     | 
    
         
            +
                                           "\x00".b
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  it 'sets tagged' do
         
     | 
| 
      
 141 
     | 
    
         
            +
                    expect(unpacked.path).to be_tagged
         
     | 
| 
      
 142 
     | 
    
         
            +
                  end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                  it 'sets tags' do
         
     | 
| 
      
 145 
     | 
    
         
            +
                    expect(unpacked.path.tag_ids).to eq [0, 1]
         
     | 
| 
      
 146 
     | 
    
         
            +
                  end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                  it 'device should be nil' do
         
     | 
| 
      
 149 
     | 
    
         
            +
                    expect(unpacked.path.device_id).to be_nil
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                context 'packing with device' do
         
     | 
| 
      
 154 
     | 
    
         
            +
                  let(:msg) do
         
     | 
| 
      
 155 
     | 
    
         
            +
                    LIFX::LAN::Message.new({
         
     | 
| 
      
 156 
     | 
    
         
            +
                      path: LIFX::LAN::ProtocolPath.new(device_id: '0123456789ab', site_id: '0' * 12),
         
     | 
| 
      
 157 
     | 
    
         
            +
                      at_time: 9001,
         
     | 
| 
      
 158 
     | 
    
         
            +
                      payload: LIFX::LAN::Protocol::Device::GetTime.new
         
     | 
| 
      
 159 
     | 
    
         
            +
                    })
         
     | 
| 
      
 160 
     | 
    
         
            +
                  end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                  let(:unpacked) { LIFX::LAN::Message.unpack(msg.pack) }
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  it 'packs the tag correctly' do
         
     | 
| 
      
 165 
     | 
    
         
            +
                    expect(msg.pack).to eq "$\x00\x00\x14\x00\x00\x00\x00\x01#Eg\x89\xAB" \
         
     | 
| 
      
 166 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)#"   \
         
     | 
| 
      
 167 
     | 
    
         
            +
                                           "\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00".b
         
     | 
| 
      
 168 
     | 
    
         
            +
                  end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  it 'sets tagged to false' do
         
     | 
| 
      
 171 
     | 
    
         
            +
                    expect(unpacked.path).not_to be_tagged
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                  it 'sets device' do
         
     | 
| 
      
 175 
     | 
    
         
            +
                    expect(unpacked.path.device_id).to eq '0123456789ab'
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  it 'tags should be nil' do
         
     | 
| 
      
 179 
     | 
    
         
            +
                    expect(unpacked.path.tag_ids).to be_nil
         
     | 
| 
      
 180 
     | 
    
         
            +
                  end
         
     | 
| 
      
 181 
     | 
    
         
            +
                end
         
     | 
| 
      
 182 
     | 
    
         
            +
              end
         
     | 
| 
      
 183 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,109 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module LIFX
         
     | 
| 
      
 4 
     | 
    
         
            +
              module LAN
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe ProtocolPath do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  describe 'initializing from raw data' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    subject do
         
     | 
| 
      
 8 
     | 
    
         
            +
                      ProtocolPath.new(raw_site: '1lifx1', raw_target: target, tagged: tagged)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    context 'device target' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                      let(:target) { "\xAB\xCD\xEF\x12\x34\x56\x00\x00" }
         
     | 
| 
      
 13 
     | 
    
         
            +
                      let(:tagged) { false }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      it 'returns site_id in hex' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                        expect(subject.site_id).to eq '316c69667831'
         
     | 
| 
      
 17 
     | 
    
         
            +
                      end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                      it 'returns device_id in hex' do
         
     | 
| 
      
 20 
     | 
    
         
            +
                        expect(subject.device_id).to eq 'abcdef123456'
         
     | 
| 
      
 21 
     | 
    
         
            +
                      end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                      it 'returns tagged as false' do
         
     | 
| 
      
 24 
     | 
    
         
            +
                        expect(subject).not_to be_tagged
         
     | 
| 
      
 25 
     | 
    
         
            +
                      end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                      it 'returns nil for tag_ids' do
         
     | 
| 
      
 28 
     | 
    
         
            +
                        expect(subject.tag_ids).to be_nil
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    context 'tagged target' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                      let(:target) { "\x03\x00\x00\x00\x00\x00\x00\x00" }
         
     | 
| 
      
 34 
     | 
    
         
            +
                      let(:tagged) { true }
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                      it 'returns site_id in hex' do
         
     | 
| 
      
 37 
     | 
    
         
            +
                        expect(subject.site_id).to eq '316c69667831'
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                      it 'returns device_id as nil' do
         
     | 
| 
      
 41 
     | 
    
         
            +
                        expect(subject.device_id).to be_nil
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                      it 'returns tagged as true' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                        expect(subject).to be_tagged
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                      it 'returns the tag_ids' do
         
     | 
| 
      
 49 
     | 
    
         
            +
                        expect(subject.tag_ids).to eq [0, 1]
         
     | 
| 
      
 50 
     | 
    
         
            +
                      end
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  describe 'initializing from strings' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    context 'device target' do
         
     | 
| 
      
 56 
     | 
    
         
            +
                      subject do
         
     | 
| 
      
 57 
     | 
    
         
            +
                        ProtocolPath.new(site_id: '316c69667831', device_id: 'abcdef123456')
         
     | 
| 
      
 58 
     | 
    
         
            +
                      end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                      it 'sets raw_site correctly' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                        expect(subject.raw_site).to eq '1lifx1'
         
     | 
| 
      
 62 
     | 
    
         
            +
                      end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                      it 'sets raw_target correctly' do
         
     | 
| 
      
 65 
     | 
    
         
            +
                        expect(subject.raw_target).to eq "\xAB\xCD\xEF\x12\x34\x56\x00\x00".b
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      it 'sets tagged to false' do
         
     | 
| 
      
 69 
     | 
    
         
            +
                        expect(subject).to_not be_tagged
         
     | 
| 
      
 70 
     | 
    
         
            +
                      end
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    context 'tagged target' do
         
     | 
| 
      
 74 
     | 
    
         
            +
                      subject do
         
     | 
| 
      
 75 
     | 
    
         
            +
                        ProtocolPath.new(site_id: '316c69667831', tag_ids: [0, 1])
         
     | 
| 
      
 76 
     | 
    
         
            +
                      end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                      it 'sets raw_site properly' do
         
     | 
| 
      
 79 
     | 
    
         
            +
                        expect(subject.raw_site).to eq '1lifx1'
         
     | 
| 
      
 80 
     | 
    
         
            +
                      end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                      it 'sets raw_target correctly' do
         
     | 
| 
      
 83 
     | 
    
         
            +
                        expect(subject.raw_target).to eq "\x03\x00\x00\x00\x00\x00\x00\x00".b
         
     | 
| 
      
 84 
     | 
    
         
            +
                      end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                      it 'returns tagged as true' do
         
     | 
| 
      
 87 
     | 
    
         
            +
                        expect(subject).to be_tagged
         
     | 
| 
      
 88 
     | 
    
         
            +
                      end
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    context 'tagged target with no site' do
         
     | 
| 
      
 92 
     | 
    
         
            +
                      subject { ProtocolPath.new(tagged: true) }
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                      it 'raw_site should be null string' do
         
     | 
| 
      
 95 
     | 
    
         
            +
                        expect(subject.raw_site).to eq "\x00\x00\x00\x00\x00\x00".b
         
     | 
| 
      
 96 
     | 
    
         
            +
                      end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                      it 'sets raw_target correctly' do
         
     | 
| 
      
 99 
     | 
    
         
            +
                        expect(subject.raw_target).to eq "\x00\x00\x00\x00\x00\x00\x00\x00".b
         
     | 
| 
      
 100 
     | 
    
         
            +
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                      it 'returns tagged as true' do
         
     | 
| 
      
 103 
     | 
    
         
            +
                        expect(subject).to be_tagged
         
     | 
| 
      
 104 
     | 
    
         
            +
                      end
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module LIFX
         
     | 
| 
      
 4 
     | 
    
         
            +
              module LAN
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe RoutingManager do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  describe '#tags_for_device_id' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    subject(:manager) { RoutingManager.new(context: double(timers: double(every: double))) }
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    before do
         
     | 
| 
      
 10 
     | 
    
         
            +
                      ['Some label', 'Another label', 'Much label'].each_with_index do |lbl, i|
         
     | 
| 
      
 11 
     | 
    
         
            +
                        manager.tag_table.update_table(device_id: 'device', tag_id: i, label: lbl)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                      manager.routing_table
         
     | 
| 
      
 15 
     | 
    
         
            +
                             .update_table(site_id: 'site', device_id: 'device', tag_ids: [0, 2])
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    it 'resolves tags' do
         
     | 
| 
      
 19 
     | 
    
         
            +
                      tags = manager.tags_for_device_id('device')
         
     | 
| 
      
 20 
     | 
    
         
            +
                      expect(tags).to eq ['Some label', 'Much label']
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module LIFX
         
     | 
| 
      
 4 
     | 
    
         
            +
              module LAN
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe RoutingTable do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  describe '#clear_stale_entries' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    subject(:table) { RoutingTable.new }
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    before do
         
     | 
| 
      
 10 
     | 
    
         
            +
                      table.update_table(site_id: 'site', device_id: 'stale device', last_seen: Time.now - 305)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      table.update_table(site_id: 'site', device_id: 'recent device', last_seen: Time.now)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    it 'clears only entries older than 5 minutes' do
         
     | 
| 
      
 15 
     | 
    
         
            +
                      expect(table.entries.count).to eq(2)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      table.clear_stale_entries
         
     | 
| 
      
 17 
     | 
    
         
            +
                      expect(table.entries.count).to eq(1)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      expect(table.entries.first.device_id).to eq('recent device')
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'bundler'
         
     | 
| 
      
 2 
     | 
    
         
            +
            Bundler.require
         
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'pry'
         
     | 
| 
      
 5 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 6 
     | 
    
         
            +
            end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            require 'lifx-lan'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'lifx/lan/utilities'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            shared_context 'integration', integration: true do
         
     | 
| 
      
 12 
     | 
    
         
            +
              def lifx
         
     | 
| 
      
 13 
     | 
    
         
            +
                $lifx ||= begin
         
     | 
| 
      
 14 
     | 
    
         
            +
                  c = LIFX::LAN::Client.lan
         
     | 
| 
      
 15 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 16 
     | 
    
         
            +
                    c.discover! do
         
     | 
| 
      
 17 
     | 
    
         
            +
                      c.tags.include?('_Test') && c.lights.with_tag('_Test').count > 0
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  rescue LIFX::Client::DiscoveryTimeout
         
     | 
| 
      
 20 
     | 
    
         
            +
                    raise "Could not find any lights with tag _Test in #{c.lights.inspect}"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  c
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def flush
         
     | 
| 
      
 27 
     | 
    
         
            +
                lifx.flush
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              let(:lights) { lifx.lights.with_tag('_Test') }
         
     | 
| 
      
 31 
     | 
    
         
            +
              let(:light) { lights.first }
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            module SpecHelpers
         
     | 
| 
      
 35 
     | 
    
         
            +
              def wait(timeout: 5, retry_wait: 0.1, &block)
         
     | 
| 
      
 36 
     | 
    
         
            +
                Timeout.timeout(timeout) do
         
     | 
| 
      
 37 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 38 
     | 
    
         
            +
                    block.call
         
     | 
| 
      
 39 
     | 
    
         
            +
                  rescue RSpec::Expectations::ExpectationNotMetError
         
     | 
| 
      
 40 
     | 
    
         
            +
                    lights.refresh
         
     | 
| 
      
 41 
     | 
    
         
            +
                    sleep(retry_wait)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    retry
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              rescue Timeout::Error
         
     | 
| 
      
 46 
     | 
    
         
            +
                block.call
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            LIFX::LAN::Config.logger = Yell.new(STDERR) if ENV['DEBUG']
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            RSpec.configure do |config|
         
     | 
| 
      
 53 
     | 
    
         
            +
              config.include(SpecHelpers)
         
     | 
| 
      
 54 
     | 
    
         
            +
              config.formatter = 'documentation'
         
     | 
| 
      
 55 
     | 
    
         
            +
              config.color = true
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     |