mbox 0.0.4 → 0.0.4.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.
@@ -42,28 +42,33 @@ end.parse!
42
42
  end
43
43
  }
44
44
 
45
- class Connection < EventMachine::Protocols::LineAndTextProtocol
46
- @@unread = {}
45
+ $unread = {}
47
46
 
47
+ class Connection < EventMachine::Protocols::LineAndTextProtocol
48
48
  attr_accessor :boxes
49
49
 
50
50
  def receive_line (line)
51
51
  whole, target, command, rest = line.match(/^(.*?)\s+(.*?)(?:\s+(.+))?$/).to_a
52
52
 
53
- boxes = target == '*' ? @boxes : @boxes.select { |box| target.include? box.name }
53
+ boxes = target == '*' ? $boxes : $boxes.select { |box| target.include? box.name }
54
54
 
55
55
  if command == 'list'
56
56
  command = rest
57
57
 
58
58
  if command == 'unread'
59
- send_response boxes.select { |box|
60
- if @@unread[box] && @@unread[box].last_check < [File.ctime(box.path), File.mtime(box.path)].max
61
- @@unread[box] = Struct.new(:status, :last_check).new(box.has_unread?, Time.new)
62
- else
63
- @@unread[box] ||= Struct.new(:status, :last_check).new(box.has_unread?, Time.new)
59
+ send_response boxes.select {|box|
60
+ if !$unread[box] || $unread[box].last_check < [File.ctime(box.path), File.mtime(box.path)].max
61
+ unless $unread[:checking]
62
+ $unread[:checking] = true
63
+
64
+ EM.defer {
65
+ $unread[box] = Struct.new(:status, :last_check).new(box.has_unread?, Time.new)
66
+ $unread[:checking] = false
67
+ }
68
+ end
64
69
  end
65
70
 
66
- @@unread[box].status
71
+ $unread[box].status rescue false
67
72
  }.map(&:name)
68
73
  end
69
74
  end
@@ -77,15 +82,13 @@ class Connection < EventMachine::Protocols::LineAndTextProtocol
77
82
  end
78
83
 
79
84
  EM.run {
80
- boxes = options[:mail][:boxes].map {|name|
85
+ $boxes = options[:mail][:boxes].map {|name|
81
86
  Mbox.open("#{options[:mail][:directory]}/#{name}")
82
87
  }
83
88
 
84
- EM.start_server options[:host], options[:port], Connection do |c|
85
- c.boxes = boxes
86
- end
89
+ EM.start_server options[:host], options[:port], Connection
87
90
 
88
91
  EM.add_periodic_timer options[:every] do
89
- `fetchmail`
92
+ EM.system 'fetchmail'
90
93
  end
91
94
  }
@@ -34,5 +34,3 @@ if command == 'list'
34
34
  puts JSON.parse(socket.gets).join("\n")
35
35
  end
36
36
  end
37
-
38
- socket.close
@@ -35,7 +35,7 @@ class Content < Array
35
35
  headers = @headers.merge(headers)
36
36
  type = headers[:content_type]
37
37
 
38
- if matches = type.mime.match(%r{multipart/(\w+)})
38
+ if type && type.mime && matches = type.mime.match(%r{multipart/(\w+)})
39
39
  text.sub(/^.*?--#{type.boundary}\n/m, '').sub(/--#{type.boundary}--$/m, '').split("--#{type.boundary}\n").each {|part|
40
40
  stream = StringIO.new(part)
41
41
 
@@ -18,6 +18,7 @@
18
18
  #++
19
19
 
20
20
  require 'stringio'
21
+ require 'call-me/memoize'
21
22
 
22
23
  require 'mbox/mail/headers/status'
23
24
  require 'mbox/mail/headers/content_type'
@@ -25,22 +26,45 @@ require 'mbox/mail/headers/content_type'
25
26
  class Mbox; class Mail
26
27
 
27
28
  class Headers
28
- def self.name_to_symbol (name)
29
- return name if name.is_a? Symbol
29
+ class Name
30
+ def self.parse (text)
31
+ return text if text.is_a? self
30
32
 
31
- name = name.to_s.downcase.gsub('-', '_').to_sym
33
+ new(text)
34
+ end
35
+
36
+ def initialize (name)
37
+ name = name.to_s.downcase.gsub('-', '_').to_sym
32
38
 
33
- if name.empty?
34
- raise ArgumentError, 'cannot pass empty name'
39
+ if name.empty?
40
+ raise ArgumentError, 'cannot pass empty name'
41
+ end
42
+
43
+ @internal = name
35
44
  end
36
45
 
37
- name
38
- end
46
+ def == (other)
47
+ to_sym == Name.parse(other).to_sym
48
+ end
39
49
 
40
- def self.symbol_to_name (name)
41
- name.to_s.downcase.gsub('_', '-').gsub(/(\A|-)(.)/) {|match|
42
- match.upcase
43
- }
50
+ alias eql? ==
51
+
52
+ def hash
53
+ to_sym.hash
54
+ end
55
+
56
+ def to_sym
57
+ @internal
58
+ end
59
+
60
+ memoize
61
+ def to_s
62
+ to_sym.to_s.downcase.gsub('_', '-').gsub(/(\A|-)(.)/) {|match|
63
+ match.upcase
64
+ }
65
+ end
66
+
67
+ alias to_str to_s
44
68
  end
45
69
 
46
70
  def self.parse (input)
@@ -60,16 +84,16 @@ class Headers
60
84
  end
61
85
 
62
86
  def [] (name)
63
- @data[Headers.name_to_symbol(name)]
87
+ @data[Name.parse(name)]
64
88
  end
65
89
 
66
90
  def []= (name, value)
67
- name = Headers.name_to_symbol(name)
91
+ name = Name.parse(name)
68
92
 
69
- value = case name
70
- when :status then Status.parse(value)
71
- when :content_type then ContentType.parse(value)
72
- else value
93
+ if name == :status
94
+ value = Status.parse(value)
95
+ elsif name == :content_type
96
+ value = ContentType.parse(value)
73
97
  end
74
98
 
75
99
  if tmp = @data[name] && !tmp.is_a?(Array)
@@ -112,7 +136,7 @@ class Headers
112
136
 
113
137
  until input.eof? || (line = input.readline).chomp.empty?
114
138
  if !line.match(/^\s/)
115
- next unless matches = line.match(/^([^:]+):\s*(.+)$/)
139
+ next unless matches = line.match(/^([\w\-]+):\s*(.+)$/)
116
140
 
117
141
  whole, name, value = matches.to_a
118
142
 
@@ -121,7 +145,7 @@ class Headers
121
145
  elsif self[last]
122
146
  if self[last].is_a?(String)
123
147
  self[last] << " #{line}"
124
- elsif self[last].is_a?(Array)
148
+ elsif self[last].is_a?(Array) && self[last].last.is_a?(String)
125
149
  self[last].last << " #{line}"
126
150
  end
127
151
  end
@@ -135,12 +159,12 @@ class Headers
135
159
 
136
160
  each {|name, values|
137
161
  [values].flatten.each {|value|
138
- result << "#{Headers.symbol_to_name(name)}: #{value}\n"
162
+ result << "#{name}: #{value}\n"
139
163
  }
140
164
  }
141
165
 
142
166
  result
143
167
  end
144
168
  end
145
- end
146
- end
169
+
170
+ end; end
@@ -67,9 +67,17 @@ class Mbox
67
67
  def each (opts = {})
68
68
  @input.seek 0
69
69
 
70
+ if @input.respond_to? :flock
71
+ @input.flock File::LOCK_SH
72
+ end
73
+
70
74
  while mail = Mail.parse(@input, options.merge(opts))
71
75
  yield mail
72
76
  end
77
+
78
+ if @input.respond_to? :flock
79
+ @input.flock File::LOCK_UN
80
+ end
73
81
  end
74
82
 
75
83
  def [] (index, opts = {})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-06 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-05-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: call-me
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: A simple library to read mbox files.
15
31
  email: meh@paranoici.org
16
32
  executables:
@@ -50,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
66
  version: '0'
51
67
  requirements: []
52
68
  rubyforge_project:
53
- rubygems_version: 1.8.23
69
+ rubygems_version: 1.8.24
54
70
  signing_key:
55
71
  specification_version: 3
56
72
  summary: A simple library to read mbox files.