couchwatcher 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
2
2
 
3
3
  gem "json", "> 1.1.5"
4
4
  gem "typhoeus", "~> 0.2"
5
+ gem "thor", "~>0.14.0"
5
6
 
6
7
  group :development do
7
8
  gem "shoulda", ">= 0"
@@ -11,6 +11,7 @@ GEM
11
11
  rake (0.8.7)
12
12
  rcov (0.9.9)
13
13
  shoulda (2.11.3)
14
+ thor (0.14.6)
14
15
  typhoeus (0.2.4)
15
16
  mime-types
16
17
  mime-types
@@ -24,4 +25,5 @@ DEPENDENCIES
24
25
  json (> 1.1.5)
25
26
  rcov
26
27
  shoulda
28
+ thor (~> 0.14.0)
27
29
  typhoeus (~> 0.2)
@@ -11,7 +11,7 @@ This gem provides a simple library to watch a couchdb database or specific docum
11
11
 
12
12
  couch_watcher = CouchWatcher::CouchWatcher.new()
13
13
  couch_watcher.add_database_watcher('http://localhost:5984/my_database', true) {|url, id, rev, doc| puts("DATABASE: Changes detected at: #{url} id: #{id} and rev: #{rev}. \n For document: #{doc.inspect}")}
14
- couch_watcher.add_document_watcher('http://localhost:5984/my_database', '_design/mydocument', true) {|url, id, rev, doc| puts("DOCUMENT: Changes detected at: #{url} id: #{id} and rev: #{rev}. \n For document: #{doc.inspect}")}
14
+ couch_watcher.add_document_watcher('http://localhost:5984/my_database/_design/mydocument', true) {|url, id, rev, doc| puts("DOCUMENT: Changes detected at: #{url} id: #{id} and rev: #{rev}. \n For document: #{doc.inspect}")}
15
15
  couch_watcher.start_watching()
16
16
 
17
17
  == Contributing to couchwatcher
data/Rakefile CHANGED
@@ -24,6 +24,7 @@ Jeweler::Tasks.new do |gem|
24
24
 
25
25
  gem.add_dependency 'json', '> 1.1.5'
26
26
  gem.add_dependency 'typhoeus', '~>0.2'
27
+ gem.add_dependency 'thor', '~>0.14.0'
27
28
  gem.files.include 'lib/couchwatcher/database_listener.rb'
28
29
  end
29
30
  Jeweler::RubygemsDotOrgTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{couchwatcher}
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kevin Malakoff"]
12
- s.date = %q{2011-06-18}
12
+ s.date = %q{2011-06-19}
13
13
  s.description = %q{This gem provides a simple library to watch a couchdb database or specific documents and to receieve notifications when they change.}
14
14
  s.email = %q{xmann.intl@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -42,31 +42,37 @@ Gem::Specification.new do |s|
42
42
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
43
  s.add_runtime_dependency(%q<json>, ["> 1.1.5"])
44
44
  s.add_runtime_dependency(%q<typhoeus>, ["~> 0.2"])
45
+ s.add_runtime_dependency(%q<thor>, ["~> 0.14.0"])
45
46
  s.add_development_dependency(%q<shoulda>, [">= 0"])
46
47
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
47
48
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
48
49
  s.add_development_dependency(%q<rcov>, [">= 0"])
49
50
  s.add_runtime_dependency(%q<json>, ["> 1.1.5"])
50
51
  s.add_runtime_dependency(%q<typhoeus>, ["~> 0.2"])
52
+ s.add_runtime_dependency(%q<thor>, ["~> 0.14.0"])
51
53
  else
52
54
  s.add_dependency(%q<json>, ["> 1.1.5"])
53
55
  s.add_dependency(%q<typhoeus>, ["~> 0.2"])
56
+ s.add_dependency(%q<thor>, ["~> 0.14.0"])
54
57
  s.add_dependency(%q<shoulda>, [">= 0"])
55
58
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
56
59
  s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
57
60
  s.add_dependency(%q<rcov>, [">= 0"])
58
61
  s.add_dependency(%q<json>, ["> 1.1.5"])
59
62
  s.add_dependency(%q<typhoeus>, ["~> 0.2"])
63
+ s.add_dependency(%q<thor>, ["~> 0.14.0"])
60
64
  end
61
65
  else
62
66
  s.add_dependency(%q<json>, ["> 1.1.5"])
63
67
  s.add_dependency(%q<typhoeus>, ["~> 0.2"])
68
+ s.add_dependency(%q<thor>, ["~> 0.14.0"])
64
69
  s.add_dependency(%q<shoulda>, [">= 0"])
65
70
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
66
71
  s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
67
72
  s.add_dependency(%q<rcov>, [">= 0"])
68
73
  s.add_dependency(%q<json>, ["> 1.1.5"])
69
74
  s.add_dependency(%q<typhoeus>, ["~> 0.2"])
75
+ s.add_dependency(%q<thor>, ["~> 0.14.0"])
70
76
  end
71
77
  end
72
78
 
@@ -1,12 +1,16 @@
1
1
  require 'typhoeus'
2
-
3
2
  require 'couchwatcher/database_listener'
4
3
 
4
+ $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__))))
5
+
5
6
  module CouchWatcher
6
7
 
8
+ DEFAULT_POLLING_INTERVAL = 1
9
+
7
10
  class CouchWatcher
8
11
  def initialize()
9
12
  @database_listeners = {}
13
+ @verbose = true
10
14
  end
11
15
 
12
16
  def add_database_watcher(database_url, include_document, &callback_block)
@@ -17,7 +21,8 @@ module CouchWatcher
17
21
  database_listener(database_url).remove_database_callback(callback_object)
18
22
  end
19
23
 
20
- def add_document_watcher(database_url, document_id, include_document, &callback_block)
24
+ def add_document_watcher(document_url, include_document, &callback_block)
25
+ database_url, document_id = extract_url_components(document_url)
21
26
  database_listener(database_url).add_document_callback(document_id, callback_block, include_document)
22
27
  end
23
28
 
@@ -25,12 +30,14 @@ module CouchWatcher
25
30
  database_listener(database_url).remove_document_callback(callback_object)
26
31
  end
27
32
 
28
- def start_watching()
29
- @database_listeners.each {|database_url, database_listener| database_listener.start_watching()}
33
+ def start_watching(verbose=true, polling_interval=nil)
34
+ polling_interval = DEFAULT_POLLING_INTERVAL if (polling_interval.nil? || polling_interval <= 0)
35
+ @verbose = verbose
36
+ @database_listeners.each {|database_url, database_listener| database_listener.start_watching(verbose, polling_interval)}
30
37
  end
31
38
 
32
39
  def stop_watching()
33
- @database_listeners.each {|database_url, database_listener| database_listener.stop_watching()}
40
+ @database_listeners.each {|database_url, database_listener| database_listener.stop_watching(@verbose)}
34
41
  end
35
42
 
36
43
  private
@@ -45,6 +52,22 @@ module CouchWatcher
45
52
 
46
53
  return database_listener
47
54
  end
55
+
56
+ def extract_url_components(document_url)
57
+ url_elements = document_url.split('/')
58
+
59
+ # a special design type
60
+ if url_elements[url_elements.length-2].start_with?("_")
61
+ document_element = url_elements[url_elements.length-2]
62
+
63
+ # a normal document type
64
+ else
65
+ document_element = url_elements[url_elements.length-1]
66
+ end
67
+
68
+ url_elements = document_url.split(document_element)
69
+ return [url_elements[0].chomp("/"), (url_elements[1].nil? ? document_element : document_element + url_elements[1])]
70
+ end
48
71
 
49
72
  end
50
73
  end
@@ -1,33 +1,29 @@
1
1
  require 'json'
2
+ require 'thor/shell/basic'
2
3
 
3
4
  module CouchWatcher
4
5
 
5
6
  class DatabaseListener
6
7
 
7
- def initialize(database_url, polling_interval = 3)
8
+ # shortcut to say
9
+ def say(message, color=nil)
10
+ @shell ||= Thor::Shell::Basic.new
11
+ @shell.say message, color
12
+ end
13
+
14
+ def initialize(database_url)
8
15
  @database_url = database_url
9
- @polling_interval = polling_interval
10
16
  @last_sequence = nil
11
- @connection_stopped = false
12
17
  @thread = nil
13
18
  @DatabaseCallback = Struct.new(:callback_proc, :include_document)
14
19
  @database_callbacks = []
15
20
  @DocumentCallback = Struct.new(:document_id, :callback_proc, :include_document)
16
21
  @document_callbacks = []
17
-
18
- data = get_info()
19
- if data.nil?
20
- puts "Error: the database cannnot be watched: #{@database_url}. Check that the couchdb is running, the database exists, and you have adequate permissions."
21
- @connection_stopped = true
22
- return
23
- end
24
-
25
- @last_sequence = data["update_seq"]
26
22
  end
27
23
 
28
24
  def add_database_callback(callback_proc, include_document)
29
25
  if !@thread.nil?
30
- puts "Error: cannot add callbacks to a running listener"
26
+ say "Error: cannot add callbacks to a running listener", :red
31
27
  return nil
32
28
  end
33
29
 
@@ -38,7 +34,7 @@ module CouchWatcher
38
34
 
39
35
  def remove_database_callback(database_callback)
40
36
  if !@thread.nil?
41
- puts "Error: cannot remove callbacks from a running listener"
37
+ say "Error: cannot remove callbacks from a running listener", :red
42
38
  return
43
39
  end
44
40
 
@@ -47,7 +43,7 @@ module CouchWatcher
47
43
 
48
44
  def add_document_callback(document_id, callback_proc, include_document)
49
45
  if !@thread.nil?
50
- puts "Error: cannot add callbacks to a running listener"
46
+ say "Error: cannot add callbacks to a running listener", :red
51
47
  return nil
52
48
  end
53
49
 
@@ -58,23 +54,38 @@ module CouchWatcher
58
54
 
59
55
  def remove_document_callback(document_callback)
60
56
  if !@thread.nil?
61
- puts "Error: cannot remove callbacks from a running listener"
57
+ say "Error: cannot remove callbacks from a running listener", :red
62
58
  return
63
59
  end
64
60
 
65
61
  @document_callbacks.delete(document_callback)
66
62
  end
67
63
 
68
- def start_watching
64
+ def start_watching(verbose, polling_interval)
69
65
  if !@thread.nil?
70
- puts "Error: listener is already running listener"
66
+ say "Error: listener is already running listener", :red
71
67
  return
72
68
  end
73
69
 
74
- puts "Database watching started for: #{@database_url}"
70
+ say "Database watching started for: #{@database_url}", :green if verbose
75
71
  @thread = Thread.new do
72
+
73
+ # get the sequence
74
+ if @last_sequence.nil?
75
+ data = get_info()
76
+ if data.nil? || data["update_seq"].nil?
77
+ say "Error: the database cannnot be watched: #{@database_url}. Check that the couchdb is running, the database exists, and you have adequate permissions.", :red
78
+ return
79
+ end
80
+
81
+ @last_sequence = data["update_seq"]
82
+ end
83
+
84
+ @connection_stopped = false
76
85
  while true
77
86
 
87
+ #puts "Checking heartbeat: #{@database_url} sequence: #{@last_sequence} connecte"
88
+
78
89
  # stopped the connection
79
90
  if @connection_stopped
80
91
  return
@@ -82,17 +93,18 @@ module CouchWatcher
82
93
  # the sequence number has been returned so start polling
83
94
  elsif @last_sequence
84
95
  results = get_changes()
85
-
86
- # print a message
87
- # puts "Get changes heartbeat"
88
- puts "Change detected in database: #{@database_url}" if (results && !results.empty?)
89
-
96
+
97
+ #puts "Checking heartbeat: #{@database_url} sequence: #{@last_sequence}"
98
+
90
99
  results.each do |result|
91
100
 
92
101
  document_id = result["id"]
93
102
  document_rev = result["changes"][0]["rev"]
94
103
  document = result["doc"]
95
104
 
105
+ # tell a change
106
+ say "Change detected in database: #{@database_url} document: #{document_id}", :green if verbose
107
+
96
108
  # call the database watchers
97
109
  @database_callbacks.each do |callback|
98
110
  if callback.include_document
@@ -115,24 +127,22 @@ module CouchWatcher
115
127
  end
116
128
  end
117
129
 
118
- sleep @polling_interval
130
+ sleep polling_interval
119
131
  end
120
132
  end
121
133
  end
122
134
 
123
- def stop_watching
135
+ def stop_watching(verbose)
124
136
  if @thread.nil?
125
- puts "Error: listener is is not running"
137
+ say "Error: cannot stop because listener is is not running", :red
126
138
  return
127
139
  end
128
140
 
129
141
  # give the thread time to finish
130
142
  @connection_stopped = true
131
- sleep @polling_interval + 2
132
-
133
143
  @thread.kill
134
144
  @thread = nil
135
- puts "Database watching stopped for: #{@database_url}"
145
+ say "Database watching stopped for: #{@database_url}", :green if verbose
136
146
  end
137
147
 
138
148
  private
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchwatcher
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kevin Malakoff
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-18 00:00:00 +02:00
18
+ date: 2011-06-19 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -50,8 +50,24 @@ dependencies:
50
50
  version_requirements: *id002
51
51
  prerelease: false
52
52
  - !ruby/object:Gem::Dependency
53
- type: :development
53
+ type: :runtime
54
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 39
60
+ segments:
61
+ - 0
62
+ - 14
63
+ - 0
64
+ version: 0.14.0
65
+ name: thor
66
+ version_requirements: *id003
67
+ prerelease: false
68
+ - !ruby/object:Gem::Dependency
69
+ type: :development
70
+ requirement: &id004 !ruby/object:Gem::Requirement
55
71
  none: false
56
72
  requirements:
57
73
  - - ">="
@@ -61,11 +77,11 @@ dependencies:
61
77
  - 0
62
78
  version: "0"
63
79
  name: shoulda
64
- version_requirements: *id003
80
+ version_requirements: *id004
65
81
  prerelease: false
66
82
  - !ruby/object:Gem::Dependency
67
83
  type: :development
68
- requirement: &id004 !ruby/object:Gem::Requirement
84
+ requirement: &id005 !ruby/object:Gem::Requirement
69
85
  none: false
70
86
  requirements:
71
87
  - - ~>
@@ -77,11 +93,11 @@ dependencies:
77
93
  - 0
78
94
  version: 1.0.0
79
95
  name: bundler
80
- version_requirements: *id004
96
+ version_requirements: *id005
81
97
  prerelease: false
82
98
  - !ruby/object:Gem::Dependency
83
99
  type: :development
84
- requirement: &id005 !ruby/object:Gem::Requirement
100
+ requirement: &id006 !ruby/object:Gem::Requirement
85
101
  none: false
86
102
  requirements:
87
103
  - - ~>
@@ -93,11 +109,11 @@ dependencies:
93
109
  - 2
94
110
  version: 1.6.2
95
111
  name: jeweler
96
- version_requirements: *id005
112
+ version_requirements: *id006
97
113
  prerelease: false
98
114
  - !ruby/object:Gem::Dependency
99
115
  type: :development
100
- requirement: &id006 !ruby/object:Gem::Requirement
116
+ requirement: &id007 !ruby/object:Gem::Requirement
101
117
  none: false
102
118
  requirements:
103
119
  - - ">="
@@ -107,11 +123,11 @@ dependencies:
107
123
  - 0
108
124
  version: "0"
109
125
  name: rcov
110
- version_requirements: *id006
126
+ version_requirements: *id007
111
127
  prerelease: false
112
128
  - !ruby/object:Gem::Dependency
113
129
  type: :runtime
114
- requirement: &id007 !ruby/object:Gem::Requirement
130
+ requirement: &id008 !ruby/object:Gem::Requirement
115
131
  none: false
116
132
  requirements:
117
133
  - - ">"
@@ -123,11 +139,11 @@ dependencies:
123
139
  - 5
124
140
  version: 1.1.5
125
141
  name: json
126
- version_requirements: *id007
142
+ version_requirements: *id008
127
143
  prerelease: false
128
144
  - !ruby/object:Gem::Dependency
129
145
  type: :runtime
130
- requirement: &id008 !ruby/object:Gem::Requirement
146
+ requirement: &id009 !ruby/object:Gem::Requirement
131
147
  none: false
132
148
  requirements:
133
149
  - - ~>
@@ -138,7 +154,23 @@ dependencies:
138
154
  - 2
139
155
  version: "0.2"
140
156
  name: typhoeus
141
- version_requirements: *id008
157
+ version_requirements: *id009
158
+ prerelease: false
159
+ - !ruby/object:Gem::Dependency
160
+ type: :runtime
161
+ requirement: &id010 !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ hash: 39
167
+ segments:
168
+ - 0
169
+ - 14
170
+ - 0
171
+ version: 0.14.0
172
+ name: thor
173
+ version_requirements: *id010
142
174
  prerelease: false
143
175
  description: This gem provides a simple library to watch a couchdb database or specific documents and to receieve notifications when they change.
144
176
  email: xmann.intl@gmail.com