xrc 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ module Xrc
2
+ module Messages
3
+ class Base
4
+ # @return [REXML::Element] Raw element object
5
+ attr_reader :element
6
+
7
+ # @param [REXML::Element] element A message element
8
+ def initialize(element)
9
+ @element = element
10
+ end
11
+
12
+ # Returns a JID of message sender
13
+ # @return [String]
14
+ # @example
15
+ # message.from #=> "alice@example.com"
16
+ def from
17
+ @element.attribute("from").to_s
18
+ end
19
+
20
+ # Returns a JID of message address
21
+ # @return [String]
22
+ # @example
23
+ # message.to #=> "bob@example.com"
24
+ def to
25
+ @element.attribute("to").to_s
26
+ end
27
+
28
+ # Returns the type of the message
29
+ # @return [String]
30
+ # @example
31
+ # message.type #=> "groupchat"
32
+ def type
33
+ @element.attribute("type").to_s
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Xrc
2
+ module Messages
3
+ class Message < Base
4
+ # Returns the message body (e.g. Hello)
5
+ # @return [String]
6
+ # @example
7
+ # message.body #=> "Hello"
8
+ def body
9
+ @element.elements["body/text()"].to_s
10
+ end
11
+
12
+ # Returns this message in Hash format
13
+ # @return [Hash]
14
+ # @example
15
+ # message.to_hash #=> {
16
+ # :body => "bob@example.com",
17
+ # :from => "alice@example.com",
18
+ # :to => "bob@example.com",
19
+ # }
20
+ def to_hash
21
+ {
22
+ body: body,
23
+ from: from,
24
+ to: to,
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ module Xrc
2
+ module Messages
3
+ class Null < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Xrc
2
+ module Messages
3
+ class PrivateMessage < Message
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Xrc
2
+ module Messages
3
+ class RoomMessage < Message
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,29 @@
1
+ module Xrc
2
+ module Messages
3
+ class Subject < Base
4
+ # Returns the message subject (e.g. Room1)
5
+ # @return [String]
6
+ # @example
7
+ # message.subject #=> "Room1"
8
+ def subject
9
+ @element.elements["subject/text()"].to_s
10
+ end
11
+
12
+ # Returns this message in Hash format
13
+ # @return [Hash]
14
+ # @example
15
+ # message.to_hash #=> {
16
+ # :from => "alice@example.com",
17
+ # :subject => "Room1",
18
+ # :to => "bob@example.com",
19
+ # }
20
+ def to_hash
21
+ {
22
+ from: from,
23
+ to: to,
24
+ subject: subject,
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ require "active_support/core_ext/module/aliasing"
2
+ require "active_support/logger"
3
+
4
+ module Xrc
5
+ module MethodLoggable
6
+ class << self
7
+ attr_writer :logger
8
+
9
+ def logger
10
+ @logger ||= ActiveSupport::Logger.new(STDOUT)
11
+ end
12
+ end
13
+
14
+ def log(method_name, &block)
15
+ define_method("#{method_name}_with_log") do |*args|
16
+ Xrc::MethodLoggable.logger.info(instance_exec(*args, &block))
17
+ __send__("#{method_name}_without_log", *args)
18
+ end
19
+ alias_method_chain method_name, :log
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Xrc
2
+ module Namespaces
3
+ BIND = "urn:ietf:params:xml:ns:xmpp-bind"
4
+ MUC = "http://jabber.org/protocol/muc"
5
+ PING = "urn:xmpp:ping"
6
+ ROSTER = "jabber:iq:roster"
7
+ SASL = "urn:ietf:params:xml:ns:xmpp-sasl"
8
+ SESSION = "urn:ietf:params:xml:ns:xmpp-session"
9
+ TLS = "urn:ietf:params:xml:ns:xmpp-tls"
10
+ end
11
+ end
data/lib/xrc/parser.rb ADDED
@@ -0,0 +1,89 @@
1
+ module Xrc
2
+ class Parser < REXML::Parsers::SAX2Parser
3
+ EVENTS = [
4
+ :cdata,
5
+ :characters,
6
+ :end_document,
7
+ :end_element,
8
+ :start_element,
9
+ ]
10
+
11
+ attr_accessor :current
12
+
13
+ attr_reader :block, :options
14
+
15
+ def initialize(options, &block)
16
+ super(options[:socket])
17
+ @block = block
18
+ bind
19
+ end
20
+
21
+ private
22
+
23
+ def bind
24
+ EVENTS.each do |event|
25
+ listen(event) do |*args|
26
+ send(event, *args)
27
+ end
28
+ end
29
+ end
30
+
31
+ def cdata(text)
32
+ if current
33
+ cdata = REXML::CData.new(text)
34
+ current.add(cdata)
35
+ end
36
+ end
37
+
38
+ def characters(text)
39
+ if current
40
+ text = REXML::Text.new(text, current.whitespace, nil, true)
41
+ current.add(text)
42
+ end
43
+ end
44
+
45
+ def end_document
46
+ end
47
+
48
+ def end_element(uri, localname, qname)
49
+ consume if has_current? && !has_parent?
50
+ pop
51
+ end
52
+
53
+ def start_element(uri, localname, qname, attributes)
54
+ element = REXML::Element.new(qname)
55
+ element.add_attributes(attributes)
56
+ if qname == "stream:stream"
57
+ consume(element)
58
+ else
59
+ push(element)
60
+ end
61
+ end
62
+
63
+ def push(element)
64
+ if current
65
+ self.current = current.add_element(element)
66
+ else
67
+ self.current = element
68
+ end
69
+ end
70
+
71
+ def pop
72
+ if current
73
+ self.current = current.parent
74
+ end
75
+ end
76
+
77
+ def consume(element = current)
78
+ block.call(element)
79
+ end
80
+
81
+ def has_current?
82
+ !!current
83
+ end
84
+
85
+ def has_parent?
86
+ !current.parent.nil?
87
+ end
88
+ end
89
+ end
data/lib/xrc/roster.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Xrc
2
+ class Roster
3
+ # @param [REXML::Element] element An element of the response of roster requirement
4
+ def initialize(element)
5
+ @element = element
6
+ end
7
+
8
+ # Find a Xrc::User object from its JID
9
+ # @param [String] jid JID
10
+ # @return [Xrc::User]
11
+ # @return [nil]
12
+ def [](jid)
13
+ users.find {|user| user.jid == jid }
14
+ end
15
+
16
+ private
17
+
18
+ def users
19
+ @users ||= @element.elements.collect("query/item") do |item|
20
+ User.new(
21
+ jid: item.attribute("jid").to_s,
22
+ mention_name: item.attribute("mention_name").to_s,
23
+ name: item.attribute("name").to_s,
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/xrc/socket.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Xrc
2
+ class Socket < OpenSSL::SSL::SSLSocket
3
+ def sysread(*args)
4
+ super.force_encoding(Encoding::UTF_8)
5
+ end
6
+ end
7
+ end
data/lib/xrc/user.rb ADDED
@@ -0,0 +1,27 @@
1
+ module Xrc
2
+ class User
3
+ # @option attributes [String] :jid JID
4
+ # @option attributes [String] :mention_name Mention name
5
+ # @option attributes [String] :name Full name
6
+ # @example
7
+ # Xrc::Client.new(jid: "alice@example.com", mention_name: "alice", name: "Alice Liddel")
8
+ def initialize(attributes)
9
+ @attributes = attributes
10
+ end
11
+
12
+ # @return [Xrc::Jid] JID represented in a Xrc::Jid object
13
+ def jid
14
+ @jid ||= Jid.new(@attributes[:jid])
15
+ end
16
+
17
+ # @return [String] Mention name
18
+ def mention_name
19
+ @attributes[:mention_name]
20
+ end
21
+
22
+ # @return [String] Full name
23
+ def name
24
+ @attributes[:name]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Xrc
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ require "xrc"
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+ end
8
+
9
+ Xrc::MethodLoggable.logger.level = 2
@@ -0,0 +1,75 @@
1
+ require "spec_helper"
2
+ require "active_support/core_ext/string/strip"
3
+ require "stringio"
4
+
5
+ describe Xrc::Client do
6
+ after do
7
+ server.close
8
+ end
9
+
10
+ let!(:server) do
11
+ TCPServer.new(port)
12
+ end
13
+
14
+ let(:instance) do
15
+ described_class.new(*args)
16
+ end
17
+
18
+ let(:args) do
19
+ [options]
20
+ end
21
+
22
+ let(:options) do
23
+ {
24
+ jid: jid,
25
+ port: port,
26
+ }
27
+ end
28
+
29
+ let(:port) do
30
+ 5222
31
+ end
32
+
33
+ let(:jid) do
34
+ "#{node}@#{domain}/#{resource}"
35
+ end
36
+
37
+ let(:node) do
38
+ "alice"
39
+ end
40
+
41
+ let(:domain) do
42
+ "localhost"
43
+ end
44
+
45
+ let(:resource) do
46
+ "bot"
47
+ end
48
+
49
+ let(:socket) do
50
+ StringIO.new <<-EOS.strip_heredoc
51
+ <?xml version="1.0" encoding="UTF-8"?>
52
+ <stream:stream
53
+ from='#{domain}'
54
+ id='5d29a171a9472e73'
55
+ xmlns:stream='http://etherx.jabber.org/streams'
56
+ version='1.0'
57
+ xmlns='jabber:client'>
58
+ <stream:features>
59
+ <starttls xmlns='#{Namespaces::TLS}'/>
60
+ <required/>
61
+ </stream:features>
62
+ EOS
63
+ end
64
+
65
+ describe "#run" do
66
+ before do
67
+ pending
68
+ instance.stub(socket: socket)
69
+ end
70
+
71
+ it "parses received XML message" do
72
+ instance.run
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+
3
+ describe Xrc::Jid do
4
+ let(:instance) do
5
+ described_class.new(*args)
6
+ end
7
+
8
+ let(:args) do
9
+ [jid]
10
+ end
11
+
12
+ let(:jid) do
13
+ "#{node}@#{domain}/#{resource}"
14
+ end
15
+
16
+ let(:node) do
17
+ "alice"
18
+ end
19
+
20
+ let(:domain) do
21
+ "example.com"
22
+ end
23
+
24
+ let(:resource) do
25
+ "bot"
26
+ end
27
+
28
+ describe "#initialize" do
29
+ it "parses node, domain, resource sections" do
30
+ instance.node.should == node
31
+ instance.domain.should == domain
32
+ instance.resource.should == resource
33
+ end
34
+ end
35
+ end