herpes 0.0.1.2 → 0.0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/herpes CHANGED
@@ -10,8 +10,8 @@ fail 'no configuration file passed' if ARGV.empty?
10
10
 
11
11
  herpes = Herpes.load(*ARGV)
12
12
 
13
- trap 'INT' do
14
- herpes.stop!
15
- end
13
+ END {
14
+ herpes.stop
15
+ }
16
16
 
17
- herpes.start!
17
+ herpes.start
data/examples/rss.rb CHANGED
@@ -2,6 +2,7 @@ require 'herpes/rss'
2
2
  require 'herpes/email'
3
3
 
4
4
  state '~/.herpes'
5
+ save_every 5.minutes
5
6
 
6
7
  # load the RSS module
7
8
  use :rss do
@@ -18,10 +19,7 @@ use :rss do
18
19
  register 'http://feeds.feedburner.com/incomaemeglio', :smeriglia
19
20
  register 'https://github.com/blog.atom'
20
21
  end
21
- end
22
22
 
23
- # only events coming from the RSS module
24
- from :rss do
25
23
  # define some common helper methods on every event
26
24
  before do |event|
27
25
  require 'nokogiri'
data/lib/herpes/email.rb CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  require 'pony'
12
12
 
13
- Herpes::Notifier.define :email, :mail do
13
+ Herpes::Module.define :email, :mail do
14
14
  @options = %w(from to cc bcc sender subject headers charset text_part_charset message_id via via_options attachments)
15
15
 
16
16
  plain_accessor *@options
data/lib/herpes/module.rb CHANGED
@@ -29,18 +29,45 @@ class Module
29
29
 
30
30
  attr_reader :name, :aliases, :owner
31
31
  def_delegators :owner, :state
32
+ plain_accessor :check_every
32
33
 
33
34
  def initialize (name, *aliases, &block)
34
35
  @name = name
35
36
  @aliases = aliases
36
37
 
38
+ @before = []
39
+ @matchers = []
40
+ @after = []
41
+
37
42
  instance_eval &block
38
43
  end
39
44
 
40
- def =~ (other)
41
- return true if self == other
45
+ def method_missing (id, *args, &block)
46
+ return owner.__send__ id, *args, &block if owner and owner.respond_to?(id)
42
47
 
43
- name.to_s.downcase == other.to_s.downcase || aliases.any? { |a| a.to_s.downcase == other.to_s.downcase }
48
+ super
49
+ end
50
+
51
+ def owner= (value)
52
+ @owner = value
53
+
54
+ owned(value) if respond_to? :owned
55
+
56
+ if respond_to? :check
57
+ owner.every(check_every, self, &method(:check))
58
+ end
59
+
60
+ @before.each {|matcher|
61
+ owner.before *matcher.arguments, &matcher.block
62
+ }
63
+
64
+ @matchers.each {|matcher|
65
+ owner.on *matcher.arguments, &matcher.block
66
+ }
67
+
68
+ @after.each {|matcher|
69
+ owner.after *matcher.arguments, &matcher.block
70
+ }
44
71
  end
45
72
 
46
73
  def default (&block)
@@ -57,34 +84,48 @@ class Module
57
84
  clone.tap { |o| o.instance_eval &block }
58
85
  end
59
86
 
60
- def use (*)
61
- raise NotImplementedError, 'you have to use a specialized module'
62
- end
87
+ def use (owner, &block)
88
+ with {
89
+ self.owner = owner
63
90
 
64
- def inspect
65
- "#<#{self.class.name}(#{name}#{" [#{aliases.join ', '}]" unless aliases.empty?})>"
91
+ instance_eval &block
92
+ }
66
93
  end
67
- end
68
-
69
- class Generator < Module
70
- plain_accessor :check_every
71
94
 
72
- def initialize (*)
73
- super
95
+ def before (*args, &block)
96
+ if owner = self.owner
97
+ owner.from name do
98
+ owner.before *args do |*args|
99
+ owner.instance_exec *args, &block
100
+ end
101
+ end
102
+ else
103
+ @before << Struct.new(:arguments, :block).new(args, block)
104
+ end
74
105
  end
75
106
 
76
- def use (owner, &block)
77
- with(&block).tap {|o|
78
- o.instance_eval {
79
- @owner = owner
80
-
81
- owned if respond_to? :owned
107
+ def on (*args, &block)
108
+ if owner = self.owner
109
+ owner.from name do
110
+ owner.on *args do |*args|
111
+ owner.instance_exec *args, &block
112
+ end
113
+ end
114
+ else
115
+ @matchers << Struct.new(:arguments, :block).new(args, block)
116
+ end
117
+ end
82
118
 
83
- if respond_to? :check
84
- @owner.every(check_every, &method(:check))
119
+ def after (*args, &block)
120
+ if owner = self.owner
121
+ owner.from name do
122
+ owner.after *args do |*args|
123
+ owner.instance_exec *args, &block
85
124
  end
86
- }
87
- }
125
+ end
126
+ else
127
+ @after << Struct.new(:arguments, :block).new(args, block)
128
+ end
88
129
  end
89
130
 
90
131
  def dispatch (event = nil, &block)
@@ -98,31 +139,15 @@ class Generator < Module
98
139
 
99
140
  owner.dispatch(event)
100
141
  end
101
- end
102
-
103
- class Notifier < Module
104
- def initialize (*)
105
- @matchers = []
106
142
 
107
- super
108
- end
143
+ def =~ (other)
144
+ return true if self == other
109
145
 
110
- def on (*args, &block)
111
- @matchers << Struct.new(:arguments, :block).new(args, block)
146
+ name.to_s.downcase == other.to_s.downcase || aliases.any? { |a| a.to_s.downcase == other.to_s.downcase }
112
147
  end
113
148
 
114
- def use (owner, &block)
115
- with(&block).tap {|o|
116
- o.instance_eval {
117
- @owner = owner
118
-
119
- owned if respond_to? :owned
120
-
121
- @matchers.each {|matcher|
122
- @owner.on *matcher.arguments, &matcher.block
123
- }
124
- }
125
- }
149
+ def inspect
150
+ "#<#{self.class.name}(#{name}#{" [#{aliases.join ', '}]" unless aliases.empty?})>"
126
151
  end
127
152
  end
128
153
 
@@ -0,0 +1,18 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ Herpes::Module.define :nerdz do
12
+ plain_accessor :username, :password
13
+
14
+ check_every 2.minutes
15
+
16
+ def check
17
+ end
18
+ end
data/lib/herpes/rss.rb CHANGED
@@ -11,7 +11,7 @@
11
11
  require 'rss'
12
12
  require 'open-uri'
13
13
 
14
- Herpes::Generator.define :rss do
14
+ Herpes::Module.define :rss do
15
15
  plain_accessor :digest
16
16
 
17
17
  check_every 5.minutes
@@ -21,18 +21,25 @@ Herpes::Generator.define :rss do
21
21
 
22
22
  def tag (*tags, &block)
23
23
  @tags.push tags
24
- instance_eval &block
24
+ result = instance_eval &block
25
25
  @tags.pop
26
+
27
+ result
26
28
  end
27
29
 
28
30
  def group (group, &block)
29
31
  @group, tmp = group, @group
30
- instance_eval &block
32
+ result = instance_eval &block
31
33
  @group = tmp
34
+
35
+ result
32
36
  end
33
37
 
34
38
  def register (url, name = nil)
35
39
  @rss << Struct.new(:url, :name, :tags, :group).new(url, name, @tags.flatten, @group)
40
+ @rss.uniq!
41
+
42
+ self
36
43
  end
37
44
 
38
45
  def check
@@ -0,0 +1,13 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ Herpes::Module.define :server do
12
+ plain_accessor :bind, :port
13
+ end
@@ -10,6 +10,6 @@
10
10
 
11
11
  class Herpes
12
12
  def self.version
13
- '0.0.1.2'
13
+ '0.0.2.1'
14
14
  end
15
15
  end
data/lib/herpes.rb CHANGED
@@ -15,14 +15,15 @@ require 'herpes/module'
15
15
 
16
16
  class Herpes
17
17
  class Callback
18
- attr_reader :time, :block, :last
18
+ attr_reader :time, :discriminator, :block, :last
19
19
 
20
- def initialize (time, one_shot = false, &block)
20
+ def initialize (time, discriminator, one_shot = false, &block)
21
21
  raise ArgumentError, 'no block has been passed' unless block
22
22
 
23
- @time = time
24
- @one_shot = one_shot
25
- @block = block
23
+ @time = time
24
+ @discriminator = discriminator
25
+ @one_shot = one_shot
26
+ @block = block
26
27
 
27
28
  if !one_shot?
28
29
  @last = Time.now - time
@@ -48,7 +49,7 @@ class Herpes
48
49
  end
49
50
 
50
51
  def calling!
51
- @calling = :gonna
52
+ @calling = true
52
53
  end
53
54
 
54
55
  def called!
@@ -60,12 +61,14 @@ class Herpes
60
61
  @calling == true
61
62
  end
62
63
 
63
- def call (*args, &block)
64
+ def call (herpes, &block)
64
65
  return if calling?
65
66
 
66
67
  calling!
67
- @block.call(*args, &block)
68
+ @block.call(&block)
68
69
  called!
70
+
71
+ herpes.wake_up
69
72
  end
70
73
  end
71
74
 
@@ -103,12 +106,20 @@ class Herpes
103
106
  end
104
107
  end
105
108
 
109
+ def save_every (time)
110
+ cancel { |c| c.discriminator == self }
111
+
112
+ every time, self do save end
113
+ end
114
+
106
115
  def save
107
116
  return unless @state && @path
108
117
 
109
- dump = Marshal.dump(@state)
118
+ Marshal.dump(@state).tap {|dump|
119
+ File.open(@path, 'wb') { |f| f.write(dump) }
120
+ }
110
121
 
111
- File.open(@path, 'wb') { |f| f.write(dump) }
122
+ self
112
123
  end
113
124
 
114
125
  def load (*paths)
@@ -141,17 +152,30 @@ class Herpes
141
152
  end
142
153
 
143
154
  def before (&block)
144
- @before[@current] = block
155
+ return unless block
156
+
157
+ @before[@current] << block
158
+ @before[@current].uniq!
159
+
160
+ self
145
161
  end
146
162
 
147
163
  def on (matcher, &block)
148
164
  return unless block
149
165
 
150
166
  @matchers[@current] << Struct.new(:matcher, :block).new(matcher, block)
167
+ @matchers[@current].uniq!
168
+
169
+ self
151
170
  end
152
171
 
153
172
  def after (&block)
154
- @after[@current] = block
173
+ return unless block
174
+
175
+ @after[@current] << block
176
+ @after[@current].uniq!
177
+
178
+ self
155
179
  end
156
180
 
157
181
  def dispatch (event = nil, &block)
@@ -161,10 +185,10 @@ class Herpes
161
185
 
162
186
  raise ArgumentError, 'you did not pass an Event' unless event.is_a?(Event)
163
187
 
164
- @before.each {|name, block|
188
+ @before.each {|name, blocks|
165
189
  next unless name.nil? || (event.generated_by && event.generated_by =~ name)
166
190
 
167
- block.call(event)
191
+ blocks.each { |b| b.call(event) }
168
192
  }
169
193
 
170
194
  @matchers.each {|name, matchers|
@@ -184,62 +208,82 @@ class Herpes
184
208
  }
185
209
  }
186
210
 
187
- @after.each {|name, block|
211
+ @after.each {|name, blocks|
188
212
  next unless name.nil? || (event.generated_by && event.generated_by =~ name)
189
213
 
190
- block.call(event)
214
+ blocks.each { |b| b.call(event) }
191
215
  }
192
216
  end
193
217
 
194
- def every (time, &block)
195
- @callbacks << Callback.new(time, &block)
218
+ def every (time, discriminator = nil, &block)
219
+ @callbacks << Callback.new(time, discriminator, &block)
196
220
  wake_up
197
221
  end
198
222
 
199
- def after (time, &block)
200
- @callbacks << Callback.new(time, true, &block)
223
+ def once (time, discriminator = nil, &block)
224
+ @callbacks << Callback.new(time, discriminator, true, &block)
225
+ wake_up
226
+ end; alias once_after once
227
+
228
+ def cancel (&block)
229
+ @callbacks.reject!(&block)
201
230
  wake_up
202
231
  end
203
232
 
204
233
  def until_next
205
- next_in = @callbacks.min_by(&:next_in).next_in
234
+ callbacks = @callbacks.reject(&:calling?).reject(&:gonna_call?)
235
+
236
+ return if callbacks.empty?
237
+
238
+ next_in = callbacks.min_by(&:next_in).next_in
206
239
 
207
- next_in > 0 ? next_in : nil
208
- rescue
209
- nil
240
+ next_in > 0 ? next_in : 0
210
241
  end
211
242
 
212
- def running?; !!@running; end
213
- def stopped?; !@running; end
243
+ def running?; @running; end
244
+ def stopped?; @stopped; end
214
245
 
215
- def start!
246
+ def start
216
247
  @running = true
217
248
 
218
249
  while running?
219
- sleep until_next
250
+ begin
251
+ sleep until_next
252
+ rescue Interrupt
253
+ break
254
+ end
220
255
 
221
256
  @callbacks.select {|callback|
222
257
  callback.next_in <= 0
223
- }.uniq.each {|callback|
258
+ }.each {|callback|
224
259
  @callbacks.delete(callback) if callback.one_shot?
225
260
 
226
- next if callback.gonna_call?
261
+ next if callback.gonna_call? or callback.calling?
227
262
 
228
263
  callback.gonna_call!
229
264
 
230
265
  process {
231
- callback.call
266
+ callback.call(self)
232
267
  }
233
268
  }
234
269
  end
235
270
 
236
271
  save
272
+
273
+ @stopped = true
237
274
  end
238
275
 
239
276
  def stop!
240
277
  @running = false
278
+
241
279
  wake_up
242
280
 
243
281
  @pool.kill
244
282
  end
283
+
284
+ def stop
285
+ stop!
286
+
287
+ sleep 0.01 until stopped?
288
+ end
245
289
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: herpes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.2
4
+ version: 0.0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-25 00:00:00.000000000 Z
12
+ date: 2011-12-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: threadpool
16
- requirement: &19904260 !ruby/object:Gem::Requirement
16
+ requirement: &10404920 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *19904260
24
+ version_requirements: *10404920
25
25
  description:
26
26
  email: meh@paranoici.org
27
27
  executables:
@@ -39,7 +39,9 @@ files:
39
39
  - lib/herpes/event.rb
40
40
  - lib/herpes/extensions.rb
41
41
  - lib/herpes/module.rb
42
+ - lib/herpes/nerdz.rb
42
43
  - lib/herpes/rss.rb
44
+ - lib/herpes/server.rb
43
45
  - lib/herpes/version.rb
44
46
  homepage: http://github.com/meh/herpes
45
47
  licenses: []