urbit-api 0.3.0 → 0.4.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 +4 -4
- data/lib/urbit/bucket.rb +45 -0
- data/lib/urbit/channel.rb +4 -5
- data/lib/urbit/fact/base_fact.rb +99 -0
- data/lib/urbit/fact/graph_fact.rb +92 -0
- data/lib/urbit/fact/group_fact.rb +124 -0
- data/lib/urbit/fact/settings_fact.rb +120 -0
- data/lib/urbit/fact.rb +40 -196
- data/lib/urbit/group.rb +109 -0
- data/lib/urbit/group_manager.rb +100 -0
- data/lib/urbit/group_parser.rb +71 -0
- data/lib/urbit/message.rb +2 -2
- data/lib/urbit/parser.rb +10 -4
- data/lib/urbit/poke_message.rb +2 -2
- data/lib/urbit/receiver.rb +14 -4
- data/lib/urbit/settings.rb +103 -0
- data/lib/urbit/ship.rb +61 -62
- data/lib/urbit/version.rb +5 -0
- data/lib/{urbit/urbit.rb → urbit.rb} +3 -2
- data/urbit-api.gemspec +7 -8
- metadata +31 -30
- data/.gitignore +0 -25
- data/.rspec +0 -1
- data/.ruby-version +0 -2
- data/CHANGELOG.md +0 -1
- data/Gemfile +0 -6
- data/LICENSE.txt +0 -21
- data/README.gem.md +0 -4
- data/README.md +0 -266
- data/Rakefile +0 -10
- data/_config.yml +0 -2
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/test +0 -2
- data/lib/urbit/api/version.rb +0 -5
- data/lib/urbit/setting.rb +0 -30
- data/misc/graph-store_graph +0 -51
- data/misc/graph-store_keys +0 -15
- data/misc/graph-store_node +0 -34
- data/misc/graph-store_update +0 -76
- data/misc/graph-update_add-graph +0 -20
- data/misc/graph-update_add-nodes +0 -75
- data/misc/post +0 -12
- data/misc/settings-store.json +0 -52
    
        data/lib/urbit/fact.rb
    CHANGED
    
    | @@ -1,206 +1,50 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require 'urbit/node'
         | 
| 3 | 
            -
            require 'urbit/parser'
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 4 2 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
                def initialize(channel:, event:)
         | 
| 10 | 
            -
                  @channel = channel
         | 
| 11 | 
            -
                  @data = event.data
         | 
| 12 | 
            -
                  @type = event.type
         | 
| 13 | 
            -
                  puts "Received a Fact for [#{channel}] -- [#{@type}] -- [#{@data}]"
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                #
         | 
| 17 | 
            -
                # This is a Facotry method to make the proper Fact subclass from
         | 
| 18 | 
            -
                # a Channel Event.
         | 
| 19 | 
            -
                #
         | 
| 20 | 
            -
                def self.collect(channel:, event:)
         | 
| 21 | 
            -
                  contents = JSON.parse(event.data)
         | 
| 22 | 
            -
                  return Fact.new(channel: channel, event: event)              if contents["json"].nil?
         | 
| 23 | 
            -
                  return SettingsEventFact.new(channel: channel, event: event) if contents["json"]["settings-event"]
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  return Fact.new(channel: channel, event: event)              if contents["json"]["graph-update"].nil?
         | 
| 26 | 
            -
                  return AddGraphFact.new(channel: channel, event: event)      if contents["json"]["graph-update"]["add-graph"]
         | 
| 27 | 
            -
                  return AddNodesFact.new(channel: channel, event: event)      if contents["json"]["graph-update"]["add-nodes"]
         | 
| 28 | 
            -
                  return RemoveGraphFact.new(channel: channel, event: event)   if contents["json"]["graph-update"]["remove-graph"]
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                  return Fact.new(channel: channel, event: event)
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                def add_ack(ack:)
         | 
| 34 | 
            -
                  @ack = :ack
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                def contents
         | 
| 38 | 
            -
                  JSON.parse(@data)
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                def for_this_ship?
         | 
| 42 | 
            -
                  self.ship == @channel.ship
         | 
| 43 | 
            -
                end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                def graph_update?
         | 
| 46 | 
            -
                  false
         | 
| 47 | 
            -
                end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                def is_acknowledged?
         | 
| 50 | 
            -
                  !@ack.nil?
         | 
| 51 | 
            -
                end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                def raw_json
         | 
| 54 | 
            -
                  nil
         | 
| 55 | 
            -
                end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                def ship
         | 
| 58 | 
            -
                  @channel.ship
         | 
| 59 | 
            -
                end
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                def to_h
         | 
| 62 | 
            -
                  {
         | 
| 63 | 
            -
                    ship:            self.ship.to_h,
         | 
| 64 | 
            -
                    acknowleged:     self.is_acknowledged?,
         | 
| 65 | 
            -
                    is_graph_update: self.graph_update?
         | 
| 66 | 
            -
                  }
         | 
| 67 | 
            -
                end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                def to_s
         | 
| 70 | 
            -
                  "a #{self.class.name}(#{self.to_h})"
         | 
| 71 | 
            -
                end
         | 
| 72 | 
            -
              end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
              class GraphUpdateFact < Fact
         | 
| 75 | 
            -
                def initialize(channel:, event:)
         | 
| 76 | 
            -
                  super channel: channel, event: event
         | 
| 77 | 
            -
                end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                #
         | 
| 80 | 
            -
                # Attach this new fact as a node to its Graph.
         | 
| 81 | 
            -
                #
         | 
| 82 | 
            -
                def attach_parser
         | 
| 83 | 
            -
                  # puts "Received a graph update for [#{self.ship.graph(resource: self.resource)}]"
         | 
| 84 | 
            -
                  if self.incoming_graph
         | 
| 85 | 
            -
                    # puts "Received an add_graph event: #{self.raw_json} on #{self.resource}"
         | 
| 86 | 
            -
                    self.create_parser
         | 
| 87 | 
            -
                  end
         | 
| 88 | 
            -
                end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                def create_parser
         | 
| 91 | 
            -
                  nil
         | 
| 92 | 
            -
                end
         | 
| 93 | 
            -
             | 
| 94 | 
            -
                def graph_update?
         | 
| 95 | 
            -
                  true
         | 
| 96 | 
            -
                end
         | 
| 97 | 
            -
             | 
| 98 | 
            -
                def incoming_graph
         | 
| 99 | 
            -
                  self.ship.graph(resource: self.resource)
         | 
| 100 | 
            -
                end
         | 
| 101 | 
            -
             | 
| 102 | 
            -
                def resource
         | 
| 103 | 
            -
                  return "~#{self.resource_h["ship"]}/#{self.resource_h["name"]}" unless self.resource_h.nil?
         | 
| 104 | 
            -
                end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                def resource_h
         | 
| 107 | 
            -
                  self.raw_json["resource"]
         | 
| 108 | 
            -
                end
         | 
| 109 | 
            -
             | 
| 110 | 
            -
                def root_h
         | 
| 111 | 
            -
                  self.contents["json"]["graph-update"]
         | 
| 112 | 
            -
                end
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                def to_h
         | 
| 115 | 
            -
                  super.merge!(resource: self.resource)
         | 
| 116 | 
            -
                end
         | 
| 117 | 
            -
              end
         | 
| 118 | 
            -
             | 
| 119 | 
            -
              class AddGraphFact < GraphUpdateFact
         | 
| 120 | 
            -
                def initialize(channel:, event:)
         | 
| 121 | 
            -
                  super channel: channel, event: event
         | 
| 122 | 
            -
                end
         | 
| 123 | 
            -
             | 
| 124 | 
            -
                def create_parser
         | 
| 125 | 
            -
                  Urbit::AddGraphParser.new(for_graph: incoming_graph,  with_json: self.raw_json).add_nodes
         | 
| 126 | 
            -
                end
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                def raw_json
         | 
| 129 | 
            -
                  self.root_h["add-graph"]
         | 
| 130 | 
            -
                end
         | 
| 131 | 
            -
              end
         | 
| 132 | 
            -
             | 
| 133 | 
            -
              class AddNodesFact < GraphUpdateFact
         | 
| 134 | 
            -
                def initialize(channel:, event:)
         | 
| 135 | 
            -
                  super channel: channel, event: event
         | 
| 136 | 
            -
                end
         | 
| 137 | 
            -
             | 
| 138 | 
            -
                def create_parser
         | 
| 139 | 
            -
                  Urbit::AddNodesParser.new(for_graph: incoming_graph,  with_json: self.raw_json).add_nodes
         | 
| 140 | 
            -
                end
         | 
| 141 | 
            -
             | 
| 142 | 
            -
                def raw_json
         | 
| 143 | 
            -
                  self.root_h["add-nodes"]
         | 
| 144 | 
            -
                end
         | 
| 145 | 
            -
              end
         | 
| 146 | 
            -
             | 
| 147 | 
            -
              class RemoveGraphFact < GraphUpdateFact
         | 
| 148 | 
            -
                def initialize(channel:, event:)
         | 
| 149 | 
            -
                  super channel: channel, event: event
         | 
| 150 | 
            -
                end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                def create_parser
         | 
| 153 | 
            -
                  Urbit::RemoveGraphParser.new(for_graph: incoming_graph,  with_json: self.raw_json)
         | 
| 154 | 
            -
                end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
                def raw_json
         | 
| 157 | 
            -
                  self.root_h["remove-graph"]
         | 
| 158 | 
            -
                end
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                def resource_h
         | 
| 161 | 
            -
                  self.raw_json
         | 
| 162 | 
            -
                end
         | 
| 163 | 
            -
              end
         | 
| 3 | 
            +
            require_relative 'fact/base_fact'
         | 
| 4 | 
            +
            require_relative 'fact/graph_fact'
         | 
| 5 | 
            +
            require_relative 'fact/group_fact'
         | 
| 6 | 
            +
            require_relative 'fact/settings_fact'
         | 
| 164 7 |  | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
                   | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 8 | 
            +
            module Urbit
         | 
| 9 | 
            +
              module Fact
         | 
| 10 | 
            +
                class << self
         | 
| 11 | 
            +
                  #
         | 
| 12 | 
            +
                  # This is a Factory method to make the proper Fact subclass from a Channel Event.
         | 
| 13 | 
            +
                  #
         | 
| 14 | 
            +
                  def collect(channel:, event:)
         | 
| 15 | 
            +
                    contents = JSON.parse(event.data)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    if contents["json"].nil?
         | 
| 18 | 
            +
                      return SuccessFact.new(channel: channel, event: event) if contents["ok"]
         | 
| 19 | 
            +
                      return ErrorFact.new(channel: channel, event: event)   if contents["err"]
         | 
| 20 | 
            +
                      return EmptyFact.new(channel: channel, event: event)
         | 
| 173 21 | 
             
                    end
         | 
| 174 | 
            -
                  end
         | 
| 175 | 
            -
                end
         | 
| 176 22 |  | 
| 177 | 
            -
             | 
| 178 | 
            -
                   | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
                  JSON.parse(@data)["json"]["settings-event"]["put-entry"]
         | 
| 183 | 
            -
                end
         | 
| 184 | 
            -
             | 
| 185 | 
            -
                def desk
         | 
| 186 | 
            -
                  self.contents["desk"]
         | 
| 187 | 
            -
                end
         | 
| 23 | 
            +
                    if contents["json"]["graph-update"]
         | 
| 24 | 
            +
                      return AddGraphFact.new(channel: channel, event: event)      if contents["json"]["graph-update"]["add-graph"]
         | 
| 25 | 
            +
                      return AddNodesFact.new(channel: channel, event: event)      if contents["json"]["graph-update"]["add-nodes"]
         | 
| 26 | 
            +
                      return RemoveGraphFact.new(channel: channel, event: event)   if contents["json"]["graph-update"]["remove-graph"]
         | 
| 27 | 
            +
                    end
         | 
| 188 28 |  | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
                 | 
| 29 | 
            +
                    if (c = contents["json"]["groupUpdate"])
         | 
| 30 | 
            +
                      return AddGroupFact.new(channel: channel, event: event)          if c["addGroup"]
         | 
| 31 | 
            +
                      return AddGroupMemberFact.new(channel: channel, event: event)    if c["addMembers"]
         | 
| 32 | 
            +
                      return AddTagFact.new(channel: channel, event: event)            if c["addTag"]
         | 
| 33 | 
            +
                      return InitialGroupFact.new(channel: channel, event: event)      if c["initial"]
         | 
| 34 | 
            +
                      return InitialGroupGroupFact.new(channel: channel, event: event) if c["initialGroup"]
         | 
| 35 | 
            +
                      return RemoveGroupMemberFact.new(channel: channel, event: event) if c["removeMembers"]
         | 
| 36 | 
            +
                      return RemoveTagFact.new(channel: channel, event: event)         if c["removeTag"]
         | 
| 37 | 
            +
                    end
         | 
| 192 38 |  | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
                     | 
| 199 | 
            -
                  })
         | 
| 200 | 
            -
                end
         | 
| 39 | 
            +
                    if (c = contents["json"]["settings-event"])
         | 
| 40 | 
            +
                      return SettingsEventDelBucketFact.new(channel: channel, event: event) if c["del-bucket"]
         | 
| 41 | 
            +
                      return SettingsEventDelEntryFact.new(channel: channel, event: event)  if c["del-entry"]
         | 
| 42 | 
            +
                      return SettingsEventPutBucketFact.new(channel: channel, event: event) if c["put-bucket"]
         | 
| 43 | 
            +
                      return SettingsEventPutEntryFact.new(channel: channel, event: event)  if c["put-entry"]
         | 
| 44 | 
            +
                    end
         | 
| 201 45 |  | 
| 202 | 
            -
             | 
| 203 | 
            -
                   | 
| 46 | 
            +
                    return BaseFact.new(channel: channel, event: event)
         | 
| 47 | 
            +
                  end
         | 
| 204 48 | 
             
                end
         | 
| 205 49 | 
             
              end
         | 
| 206 50 | 
             
            end
         | 
    
        data/lib/urbit/group.rb
    ADDED
    
    | @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Urbit
         | 
| 4 | 
            +
              class Group
         | 
| 5 | 
            +
                 attr_accessor :manager, :members, :tags
         | 
| 6 | 
            +
                 attr_reader :hidden, :path, :policy
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(path:, members:, policy:, tags:, hidden:)
         | 
| 9 | 
            +
                  @hidden  = hidden
         | 
| 10 | 
            +
                  @manager = nil
         | 
| 11 | 
            +
                  @members = Set.new(members)
         | 
| 12 | 
            +
                  @path    = path
         | 
| 13 | 
            +
                  @policy  = policy
         | 
| 14 | 
            +
                  @tags    = self.parse_tags(tags)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def ==(another_group)
         | 
| 18 | 
            +
                  another_group.path == self.path
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def <=>(another_group)
         | 
| 22 | 
            +
                  self.path <=> another_group.path
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                #
         | 
| 26 | 
            +
                # This is the action labeled as "Archive" in the Landscape UI.
         | 
| 27 | 
            +
                # As of now, you can only do this to groups on your own ship.
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                def delete
         | 
| 30 | 
            +
                  if (self.host == self.manager.ship.name)
         | 
| 31 | 
            +
                    spdr = self.manager.spider('group-delete', %Q({"remove": {"ship": "#{self.host}", "name": "#{self.key}"}}))
         | 
| 32 | 
            +
                    self.manager.remove(self) if 200 == spdr[:status]
         | 
| 33 | 
            +
                    return spdr
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                  {status: 400, code: 'bad_request', body: 'Can only delete Groups on your own ship.'}
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def eql?(another_group)
         | 
| 39 | 
            +
                  another_group.path == self.path
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def host
         | 
| 43 | 
            +
                  self.path_tokens[0]
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def invite(ship_names:, message:)
         | 
| 47 | 
            +
                  data = %Q({
         | 
| 48 | 
            +
                    "invite": {
         | 
| 49 | 
            +
                      "resource": {
         | 
| 50 | 
            +
                        "ship": "#{self.host}",
         | 
| 51 | 
            +
                        "name": "#{self.key}"
         | 
| 52 | 
            +
                      },
         | 
| 53 | 
            +
                      "ships": [
         | 
| 54 | 
            +
                        "#{ship_names.join(',')}"
         | 
| 55 | 
            +
                      ],
         | 
| 56 | 
            +
                      "description": "#{message}"
         | 
| 57 | 
            +
                    }
         | 
| 58 | 
            +
                  })
         | 
| 59 | 
            +
                  self.manager.spider('group-invite', data)
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def key
         | 
| 63 | 
            +
                  self.path_tokens[1]
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def leave
         | 
| 67 | 
            +
                  spdr = self.manager.spider('group-leave', %Q({"leave": {"ship": "#{self.host}", "name": "#{self.key}"}}))
         | 
| 68 | 
            +
                  self.manager.remove(self) if 200 == spdr[:status]
         | 
| 69 | 
            +
                  spdr
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def path_tokens
         | 
| 73 | 
            +
                  self.path.split('/')
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                def pending_invites
         | 
| 77 | 
            +
                  if (i = @policy["invite"])
         | 
| 78 | 
            +
                    if (p = i["pending"])
         | 
| 79 | 
            +
                      return p.count
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                  '?'
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def to_h
         | 
| 86 | 
            +
                {
         | 
| 87 | 
            +
                    host:            self.host,
         | 
| 88 | 
            +
                    key:             self.key,
         | 
| 89 | 
            +
                    member_count:    self.members.count,
         | 
| 90 | 
            +
                    pending_invites: self.pending_invites,
         | 
| 91 | 
            +
                    hidden:          self.hidden
         | 
| 92 | 
            +
                  }
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def to_s
         | 
| 96 | 
            +
                  "a Group(#{self.to_h})"
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                private
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def parse_tags(tags)
         | 
| 102 | 
            +
                  h = {}
         | 
| 103 | 
            +
                  return h if tags.empty?
         | 
| 104 | 
            +
                  tags.each {|k, v| h[k] = Set.new(v)}
         | 
| 105 | 
            +
                  tags.replace(h)
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
            end
         | 
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Urbit
         | 
| 4 | 
            +
              class GroupManager
         | 
| 5 | 
            +
                attr_accessor :groups, :ship
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(ship:)
         | 
| 8 | 
            +
                  @ship   = ship
         | 
| 9 | 
            +
                  @groups = []
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                # Adds a Group to this Manager's groups collection
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                def add(a_group)
         | 
| 16 | 
            +
                  @groups << a_group
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def add_members(group_path:, ships:)
         | 
| 20 | 
            +
                  if (group = self.find(path: group_path))
         | 
| 21 | 
            +
                    group.members += ships
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def add_tag(group_path:, ships:, tag:)
         | 
| 26 | 
            +
                  if (group = self.find(path: group_path))
         | 
| 27 | 
            +
                    if (group.tags.include? tag)
         | 
| 28 | 
            +
                      group.tags[tag] += ships
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def create(name:, title:, description:)
         | 
| 34 | 
            +
                  self.spider('group-create', %Q({"create": {"name": "#{name}", "title": "#{title}", "description": "#{description}", "policy": {"open": {"banRanks": [], "banned": []}}}}))
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def empty?
         | 
| 38 | 
            +
                  self.groups.empty?
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                #
         | 
| 42 | 
            +
                # Answers the Group uniquely keyed by path:, if it exists
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                def find(path:)
         | 
| 45 | 
            +
                  if (g = self.groups.select {|g| g.path == path}.first)
         | 
| 46 | 
            +
                    g.manager = self
         | 
| 47 | 
            +
                    g
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def first
         | 
| 52 | 
            +
                  g = self.groups.first
         | 
| 53 | 
            +
                  g.manager = self
         | 
| 54 | 
            +
                  g
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def join(host:, name:, share_contact: false, auto_join: false)
         | 
| 58 | 
            +
                  data = {join: {resource: {ship: "#{host}", name: "#{name}"}, ship: "#{host}", shareContact: share_contact, app: "groups", autojoin: auto_join}}
         | 
| 59 | 
            +
                  self.ship.poke(app: 'group-view', mark: 'group-view-action', message: data)
         | 
| 60 | 
            +
                  nil
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def list
         | 
| 64 | 
            +
                  self.groups.map {|g| g.path}.join("\n")
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def remove(group)
         | 
| 68 | 
            +
                  @groups = self.groups.filter {|g| g != group}
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                def remove_members(group_path:, ships:)
         | 
| 72 | 
            +
                  if (group = self.find(path: group_path))
         | 
| 73 | 
            +
                    group.members -= ships
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def remove_tag(group_path:, ships:, tag:)
         | 
| 78 | 
            +
                  if (group = self.find(path: group_path))
         | 
| 79 | 
            +
                    if (group.tags.include? tag)
         | 
| 80 | 
            +
                      group.tags[tag] -= ships
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def load
         | 
| 86 | 
            +
                  if self.ship.logged_in?
         | 
| 87 | 
            +
                    self.ship.subscribe(app: 'group-store', path: '/groups')
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                  nil
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                def spider(thread, data)
         | 
| 93 | 
            +
                  self.ship.spider(mark_in: 'group-view-action', mark_out: 'json', thread: thread, data: data)
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def to_s
         | 
| 97 | 
            +
                  self.groups.sort.each {|g| puts g}
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
            end
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'urbit/parser'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Urbit
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              class GroupParser < Parser
         | 
| 8 | 
            +
                def resource
         | 
| 9 | 
            +
                  "~#{self.resource_hash["ship"]}/#{self.resource_hash["name"]}"
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def resource_hash
         | 
| 13 | 
            +
                  @j["resource"]
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              class AddGroupParser < GroupParser
         | 
| 18 | 
            +
                def group
         | 
| 19 | 
            +
                  Urbit::Group.new(path:    self.resource,
         | 
| 20 | 
            +
                                   members: [],
         | 
| 21 | 
            +
                                   policy:  @j["policy"],
         | 
| 22 | 
            +
                                   tags:    [],
         | 
| 23 | 
            +
                                   hidden:  @j["hidden"])
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              class ChangeTagParser < GroupParser
         | 
| 28 | 
            +
                def ships
         | 
| 29 | 
            +
                  @j["ships"]
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def tag
         | 
| 33 | 
            +
                  @j["tag"]["tag"]
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              class ChangeMemberParser < GroupParser
         | 
| 38 | 
            +
                def ships
         | 
| 39 | 
            +
                  @j["ships"]
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              class InitialGroupParser < Parser
         | 
| 44 | 
            +
                def groups
         | 
| 45 | 
            +
                  self.group_hashes.collect {|k, v| Group.new(path:    k.sub('/ship/', ''),
         | 
| 46 | 
            +
                                                              members: v["members"],
         | 
| 47 | 
            +
                                                              policy:  v["policy"],
         | 
| 48 | 
            +
                                                              tags:    v["tags"],
         | 
| 49 | 
            +
                                                              hidden:  v["hidden"])}
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def group_hashes
         | 
| 53 | 
            +
                  @j
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              class InitialGroupGroupParser < GroupParser
         | 
| 58 | 
            +
                def group
         | 
| 59 | 
            +
                  Urbit::Group.new(path:    self.resource,
         | 
| 60 | 
            +
                                   members: self.group_hash["members"],
         | 
| 61 | 
            +
                                   policy:  self.group_hash["policy"],
         | 
| 62 | 
            +
                                   tags:    self.group_hash["tags"],
         | 
| 63 | 
            +
                                   hidden:  self.group_hash["hidden"])
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def group_hash
         | 
| 67 | 
            +
                  @j["group"]
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            end
         | 
    
        data/lib/urbit/message.rb
    CHANGED
    
    | @@ -22,11 +22,11 @@ module Urbit | |
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| 24 24 | 
             
                def channel_url
         | 
| 25 | 
            -
                  "#{self.ship. | 
| 25 | 
            +
                  "#{self.ship.url}/~/channel/#{self.channel.key}"
         | 
| 26 26 | 
             
                end
         | 
| 27 27 |  | 
| 28 28 | 
             
                def request_body
         | 
| 29 | 
            -
                  self.to_a | 
| 29 | 
            +
                  JSON.generate(self.to_a)
         | 
| 30 30 | 
             
                end
         | 
| 31 31 |  | 
| 32 32 | 
             
                def ship
         | 
    
        data/lib/urbit/parser.rb
    CHANGED
    
    | @@ -3,9 +3,15 @@ require 'urbit/node' | |
| 3 3 |  | 
| 4 4 | 
             
            module Urbit
         | 
| 5 5 | 
             
              class Parser
         | 
| 6 | 
            +
                def initialize(with_json:)
         | 
| 7 | 
            +
                  @j = with_json
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              class GraphParser < Parser
         | 
| 6 12 | 
             
                def initialize(for_graph:, with_json:)
         | 
| 13 | 
            +
                  super(with_json: with_json)
         | 
| 7 14 | 
             
                  @g = for_graph
         | 
| 8 | 
            -
                  @j = with_json
         | 
| 9 15 | 
             
                end
         | 
| 10 16 |  | 
| 11 17 | 
             
                #
         | 
| @@ -33,7 +39,7 @@ module Urbit | |
| 33 39 | 
             
                end
         | 
| 34 40 | 
             
              end
         | 
| 35 41 |  | 
| 36 | 
            -
              class AddGraphParser <  | 
| 42 | 
            +
              class AddGraphParser < GraphParser
         | 
| 37 43 | 
             
                def nodes_hash
         | 
| 38 44 | 
             
                  @j["graph"]
         | 
| 39 45 | 
             
                end
         | 
| @@ -43,13 +49,13 @@ module Urbit | |
| 43 49 | 
             
                end
         | 
| 44 50 | 
             
              end
         | 
| 45 51 |  | 
| 46 | 
            -
              class AddNodesParser <  | 
| 52 | 
            +
              class AddNodesParser < GraphParser
         | 
| 47 53 | 
             
                def nodes_hash
         | 
| 48 54 | 
             
                  @j["nodes"]
         | 
| 49 55 | 
             
                end
         | 
| 50 56 | 
             
              end
         | 
| 51 57 |  | 
| 52 | 
            -
              class RemoveGraphParser <  | 
| 58 | 
            +
              class RemoveGraphParser < GraphParser
         | 
| 53 59 | 
             
                def nodes_hash
         | 
| 54 60 | 
             
                  nil
         | 
| 55 61 | 
             
                end
         | 
    
        data/lib/urbit/poke_message.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module Urbit
         | 
| 2 2 | 
             
              class PokeMessage < Message
         | 
| 3 | 
            -
                def initialize(channel:, app:, mark:,  | 
| 4 | 
            -
                  super(channel: channel, app: app, mark: mark, contents:  | 
| 3 | 
            +
                def initialize(channel:, app:, mark:, a_message_hash:)
         | 
| 4 | 
            +
                  super(channel: channel, app: app, mark: mark, contents: a_message_hash)
         | 
| 5 5 | 
             
                end
         | 
| 6 6 | 
             
              end
         | 
| 7 7 | 
             
            end
         | 
    
        data/lib/urbit/receiver.rb
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            require 'ld-eventsource'
         | 
| 2 | 
            +
            require "logger"
         | 
| 2 3 |  | 
| 3 4 | 
             
            require 'urbit/ack_message'
         | 
| 4 5 | 
             
            require 'urbit/fact'
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Urbit
         | 
| 7 8 | 
             
              class Receiver < SSE::Client
         | 
| 8 | 
            -
                attr_accessor :facts
         | 
| 9 | 
            +
                attr_accessor :errors, :facts
         | 
| 9 10 |  | 
| 10 11 | 
             
                def initialize(channel:)
         | 
| 11 | 
            -
                   | 
| 12 | 
            -
                  super(channel.url, {headers: self.headers(channel)}) do |rec|
         | 
| 12 | 
            +
                  super(channel.url, headers: self.headers(channel), logger: self.default_logger) do |rec|
         | 
| 13 13 | 
             
                    # We are now listening on a socket for SSE::Events. This block will be called for each one.
         | 
| 14 14 | 
             
                    rec.on_event do |event|
         | 
| 15 15 | 
             
                      # Wrap the returned event in a Fact.
         | 
| @@ -22,12 +22,22 @@ module Urbit | |
| 22 22 | 
             
                    end
         | 
| 23 23 |  | 
| 24 24 | 
             
                    rec.on_error do |error|
         | 
| 25 | 
            -
                      self. | 
| 25 | 
            +
                      self.errors << ["I received an error fact: #{error.class}"]
         | 
| 26 26 | 
             
                    end
         | 
| 27 27 | 
             
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  @errors   = []
         | 
| 30 | 
            +
                  @facts   = []
         | 
| 28 31 | 
             
                  @is_open = true
         | 
| 29 32 | 
             
                end
         | 
| 30 33 |  | 
| 34 | 
            +
                def default_logger
         | 
| 35 | 
            +
                  log           = ::Logger.new($stdout)
         | 
| 36 | 
            +
                  log.level     = ::Logger::WARN
         | 
| 37 | 
            +
                  log.progname  = 'ld-eventsource'
         | 
| 38 | 
            +
                  log
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 31 41 | 
             
                def open?
         | 
| 32 42 | 
             
                  @is_open
         | 
| 33 43 | 
             
                end
         |