couchwatcher 0.1.0 → 0.1.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.
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