nntp-client 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,17 +1,17 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
- --format specdoc
2
- --color
1
+ --format specdoc
2
+ --color
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in nntp.gemspec
4
- gem 'rake'
5
- gem "rspec"
6
- gem "rspec-core"
7
- gem "rspec-expectations"
8
- gem "rspec-mocks"
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nntp.gemspec
4
+ gem 'rake'
5
+ gem "rspec"
6
+ gem "rspec-core"
7
+ gem "rspec-expectations"
8
+ gem "rspec-mocks"
@@ -1,22 +1,22 @@
1
- Copyright (c) 2012 Michael Westbom
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1
+ Copyright (c) 2012 Michael Westbom
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ module NNTP
2
+ Article = Struct.new(:id, :subject, :group, :num)
3
+ end
@@ -7,7 +7,7 @@ module NNTP
7
7
  # Most communication with an NNTP server happens in a back-and-forth
8
8
  # style.
9
9
  #
10
- # The client sends a message to the server. The server will respond with a status response, and sometimes with extra data. See {https://tools.ietf.org/html/rfc3977 RFC 3977} for more details.
10
+ # The client sends a article to the server. The server will respond with a status response, and sometimes with extra data. See {https://tools.ietf.org/html/rfc3977 RFC 3977} for more details.
11
11
  #
12
12
  # This class handles this communication by providing two methods,
13
13
  # one for use when additional data is expected, and one for when it is not.
@@ -1,17 +1,22 @@
1
1
  require "nntp/group"
2
- require 'nntp/message'
2
+ require 'nntp/article'
3
3
 
4
4
  module NNTP
5
5
  # Most of the action happens here. This class describes the
6
6
  # object the user interacts with the most.
7
7
  # It is constructed by NNTP::open, but you can build your own
8
8
  # if you like.
9
+
10
+ # @!attribute [r] article
11
+ # The current article pointed to by the server or nil if unset.
12
+ # @return [NNTP::Article, nil]
9
13
  class Session
10
- attr_reader :connection, :group
14
+ attr_reader :connection, :group, :article
11
15
  # @option options [NNTP::Connection, NNTP::SSLConnection] :connection
12
16
  # The connection object.
13
17
  def initialize(options)
14
18
  @group = nil
19
+ @article = nil
15
20
  @connection = options.fetch(:connection) do
16
21
  raise ArgumentError ":connection missing"
17
22
  end
@@ -51,18 +56,18 @@ module NNTP
51
56
  end
52
57
  end
53
58
 
54
- # Fetch list of message numbers from a given group.
59
+ # Fetch list of article numbers from a given group.
55
60
  # @param group The name of the group to list defaults to {#group #group.name}
56
61
  # @param range (nil) If given, specifies the range of messages to retrieve
57
- # @return [Array<NNTP::Message>] The list of messages
58
- # (only the message numbers will be populated).
62
+ # @return [Array<NNTP::Article>] The list of messages
63
+ # (only the article numbers will be populated).
59
64
  # @see https://tools.ietf.org/html/rfc3977#section-6.1.2
60
65
  def listgroup(*args)
61
66
  messages = []
62
67
  connection.query(:listgroup, *args) do |status, data|
63
68
  if status[:code] == 211
64
69
  data.each do |line|
65
- message = Message.new
70
+ message = Article.new
66
71
  message.num = line.to_i
67
72
  messages << message
68
73
  end
@@ -71,8 +76,29 @@ module NNTP
71
76
  messages
72
77
  end
73
78
 
79
+ # Fetch ID and/or Number of an article.
80
+ #
81
+ # If an article number is passed, the current article is changed
82
+ # to the selected article. If an ID is passed, the current article
83
+ # is NOT changed.
84
+ # @param id|num The article-id or article number to be selected.
85
+ # @return [NNTP::Article, nil] a Article struct or nil upon failure.
86
+ def stat(identifier = nil)
87
+ params = [:stat]
88
+ params += [identifier.to_s] unless identifier.nil?
89
+ connection.command(*params)
90
+ if status.code == 223
91
+ message = article_from_status(status.msg)
92
+ if identifier.to_i != 0
93
+ @article = message
94
+ end
95
+ message
96
+ else
97
+ nil
98
+ end
99
+ end
74
100
  # Fetch list of messages from current group.
75
- # @return [Array<NNTP::Message>] The list of messages
101
+ # @return [Array<NNTP::Article>] The list of messages
76
102
  # (The numbers AND the subjects will be populated).
77
103
  def subjects
78
104
  subjects = []
@@ -80,7 +106,7 @@ module NNTP
80
106
  connection.query(:xhdr, "Subject", range) do |status, data|
81
107
  if status[:code] == 221
82
108
  data.each do |line|
83
- message = Message.new
109
+ message = Article.new
84
110
  message.num, message.subject = line.split(' ', 2)
85
111
  subjects << message
86
112
  end
@@ -108,6 +134,14 @@ module NNTP
108
134
  end
109
135
  end
110
136
 
137
+ def article_from_status(status_msg)
138
+ message = Article.new
139
+ num, id = status_msg.split(' ', 2)
140
+ message.num = num.to_i unless num.to_i.zero?
141
+ message.id = id
142
+ message
143
+ end
144
+
111
145
  def check_initial_status
112
146
  raise "#{status}" if [400, 502].include? connection.get_status.code
113
147
  end
@@ -1,7 +1,7 @@
1
- module NNTP
2
- Status = Struct.new(:code, :msg) do
3
- def to_s
4
- "#{self[:code]} #{self[:msg]}"
5
- end
6
- end
1
+ module NNTP
2
+ Status = Struct.new(:code, :msg) do
3
+ def to_s
4
+ "#{self[:code]} #{self[:msg]}"
5
+ end
6
+ end
7
7
  end
@@ -1,3 +1,3 @@
1
1
  module NNTP
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -100,4 +100,21 @@ describe NNTP::Session do
100
100
  message_subjects(nntp.subjects).should eq ['Foo bar', 'Baz bang']
101
101
  end
102
102
  end
103
+ describe "#stat" do
104
+ let(:article) do
105
+ msg = NNTP::Article.new
106
+ msg.num = 1
107
+ msg.id = "<foo@bar.baz>"
108
+ msg
109
+ end
110
+
111
+ it "can set the current article using an article number" do
112
+ sock.should_receive(:print).with("STAT 1\r\n")
113
+ sock.should_receive(:gets).and_return("223 1 <foo@bar.baz>\r\n")
114
+ nntp.stub(:group) {NNTP::Group.new("alt.bin.foo", 1, 2, 2)}
115
+ nntp.stat(1)
116
+ nntp.status.should eq NNTP::Status.new(223, "1 <foo@bar.baz>")
117
+ nntp.article.should eq article
118
+ end
119
+ end
103
120
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nntp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-11 00:00:00.000000000 Z
12
+ date: 2013-01-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -40,12 +40,10 @@ files:
40
40
  - LICENSE.txt
41
41
  - README.md
42
42
  - Rakefile
43
- - lib/NNTPClient.rb
44
- - lib/article.rb
45
43
  - lib/nntp.rb
44
+ - lib/nntp/article.rb
46
45
  - lib/nntp/connection.rb
47
46
  - lib/nntp/group.rb
48
- - lib/nntp/message.rb
49
47
  - lib/nntp/session.rb
50
48
  - lib/nntp/ssl_connection.rb
51
49
  - lib/nntp/status.rb
@@ -87,4 +85,3 @@ test_files:
87
85
  - spec/nntp_spec.rb
88
86
  - spec/session_spec.rb
89
87
  - spec/spec_helper.rb
90
- has_rdoc:
@@ -1,120 +0,0 @@
1
- require 'socket'
2
- require_relative 'group'
3
- require_relative 'article'
4
- require "NNTPClient/version"
5
-
6
- class NNTPClient
7
- attr_reader :socket, :status, :current_group
8
-
9
- def initialize(options = {})
10
- @socket = open_socket(options)
11
- init_attributes
12
- end
13
-
14
- def groups
15
- @groups ||= list_groups
16
- end
17
-
18
- def group(group)
19
- send_message "GROUP #{group}"
20
- self.status = get_status
21
- if status[:code] == 211
22
- self.current_group = create_group(status)
23
- end
24
- end
25
-
26
- def articles
27
- @articles ||= fetch_articles
28
- end
29
-
30
- def auth(options = {})
31
- send_message "AUTHINFO USER #{options[:user]}"
32
- self.status = get_status
33
- send_message "AUTHINFO PASS #{options[:pass]}"
34
- self.status = get_status
35
- if status[:code] == 281
36
- true
37
- else
38
- false
39
- end
40
- end
41
- private
42
- def fetch_articles
43
- send_message "XHDR Subject #{current_group.first}-"
44
- self.status = get_status
45
- return nil unless status[:code] == 221
46
- get_data_block.map do |line|
47
- article_id, article_subject = line.split(' ', 2)
48
- NNTP::Article.new(article_id, article_subject)
49
- end
50
- end
51
-
52
- def init_attributes
53
- @current_group = nil
54
- @status = nil
55
- @groups = nil
56
- @articles = nil
57
- end
58
-
59
- def create_group(status)
60
- params = status[:params]
61
- # TODO: This is ugly
62
- NNTP::Group.new(*params[1..-1])
63
- end
64
-
65
- def open_socket(options)
66
- options.fetch(:socket) {
67
- url = options.fetch(:url) { raise ArgumentError, ':url is required' }
68
- port = options.fetch(:port, 119)
69
- socket_factory = options.fetch(:socket_factory) { TCPSocket }
70
- socket_factory.new(url, port)
71
- }
72
- end
73
-
74
- def list_groups
75
- send_message "LIST"
76
- status = get_status
77
- return nil unless status[:code] == 215
78
-
79
- get_data_block
80
- end
81
-
82
- def groups=(list=[])
83
- @groups = list
84
- end
85
-
86
- def status=(status)
87
- @status = status
88
- end
89
-
90
- def current_group=(group)
91
- @current_group = group
92
- end
93
-
94
- def get_status
95
- line = get_line
96
- {
97
- :code => line[0..2].to_i,
98
- :message => line[3..-1].lstrip,
99
- :params => line.split
100
- }
101
- end
102
-
103
- def get_data_block
104
- lines = []
105
- current_line = get_line
106
- until current_line == '.'
107
- lines << current_line
108
- current_line = get_line
109
- end
110
- lines
111
- end
112
-
113
- def get_line
114
- socket.gets().chomp
115
- end
116
-
117
- def send_message(msg)
118
- socket.print "#{msg}\r\n"
119
- end
120
- end
@@ -1,7 +0,0 @@
1
- module NNTP
2
- Article = Struct.new(:number, :subject, :article_id) do
3
- def to_s
4
- subject
5
- end
6
- end
7
- end
@@ -1,3 +0,0 @@
1
- module NNTP
2
- Message = Struct.new(:id, :subject, :group, :num)
3
- end