em-pg-client-helper 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  Gemfile.lock
2
2
  /pkg
3
3
  /html
4
+ /doc
5
+ /.yardoc
@@ -0,0 +1 @@
1
+ --markup markdown
data/Rakefile CHANGED
@@ -1,5 +1,4 @@
1
- require 'rubygems'
2
- require 'bundler'
1
+ exec(*(["bundle", "exec", $PROGRAM_NAME] + ARGV)) if ENV['BUNDLE_GEMFILE'].nil?
3
2
 
4
3
  task :default => :test
5
4
 
@@ -17,13 +16,10 @@ task :release do
17
16
  sh "git release"
18
17
  end
19
18
 
20
- require 'rdoc/task'
19
+ require 'yard'
21
20
 
22
- RDoc::Task.new do |rd|
23
- rd.main = "README.md"
24
- rd.title = 'em-pg-client-helper'
25
- rd.markup = "markdown"
26
- rd.rdoc_files.include("README.md", "lib/**/*.rb")
21
+ YARD::Rake::YardocTask.new :doc do |yardoc|
22
+ yardoc.files = %w{lib/**/*.rb - README.md}
27
23
  end
28
24
 
29
25
  desc "Run guard"
@@ -26,7 +26,8 @@ Gem::Specification.new do |s|
26
26
  # Needed for guard
27
27
  s.add_development_dependency 'rb-inotify', '~> 0.9'
28
28
  s.add_development_dependency 'pry-debugger'
29
- s.add_development_dependency 'rake'
30
- s.add_development_dependency 'rdoc'
29
+ s.add_development_dependency 'rake', '~> 10.4', '>= 1.0.4.2'
30
+ s.add_development_dependency 'redcarpet'
31
31
  s.add_development_dependency 'rspec'
32
+ s.add_development_dependency 'yard'
32
33
  end
@@ -11,34 +11,37 @@ module PG::EM::Client::Helper
11
11
  # a two-element array consisting of the parameterised SQL as the first
12
12
  # element, and the array of parameters as the second element.
13
13
  #
14
+ # @param tbl [#to_s]
15
+ #
16
+ # @param params [Hash<#to_s, Object>]
17
+ #
14
18
  def insert_sql(tbl, params)
15
19
  keys = params.keys.map { |k| quote_identifier(k.to_s) }.join(',')
16
20
  vals = params.values
17
21
  val_places = (1..vals.length).to_a.map { |i| "$#{i}" }.join(',')
18
22
 
19
- ["INSERT INTO #{quote_identifier(tbl)} (#{keys}) VALUES (#{val_places})", vals]
23
+ ["INSERT INTO #{quote_identifier(tbl.to_s)} (#{keys}) VALUES (#{val_places})", vals]
20
24
  end
21
25
 
22
26
  # Run an insert query, without having to write a great pile of SQL all by
23
27
  # yourself.
24
28
  #
25
- # Arguments:
26
- #
27
- # * `db` -- A PG::EM::Client or PG::EM::ConnectionPool instance, against
28
- # which all database operations will be executed.
29
+ # @param db [PG::EM::Client, PG::EM::ConnectionPool] the connection
30
+ # against which all database operations will be run.
29
31
  #
30
- # * `tbl` -- The name of the table into which you wish to insert your data.
31
- # This parameter will be automatically quoted, if necessary.
32
+ # @param tbl [#to_s] the name of the table into which you wish to insert
33
+ # your data. This parameter will be automatically quoted, if
34
+ # necessary.
32
35
  #
33
- # * `params` -- A hash containing the fields you wish to insert into
34
- # (the keys of the hash) and the values to insert into each field (the
35
- # values of the hash). All field names and data will be automatically
36
- # quoted and made safe, so you're automatically SQL injection-proof!
36
+ # @param params [Hash<#to_s, Object>] the fields you wish to insert into
37
+ # (the keys of the hash) and the values to insert into each field (the
38
+ # values of the hash). All field names and data will be automatically
39
+ # quoted and made safe, so you're automatically SQL injection-proof!
37
40
  #
38
- # This method returns the deferrable in which the query is being called;
39
- # this means you should attach the code to run after the query completes
40
- # with `#callback`, and you can attach an error handler with `#errback`
41
- # if you like.
41
+ # @return [EM::Deferrable] the deferrable in which the query is being
42
+ # called; this means you should attach the code to run after the query
43
+ # completes with `#callback`, and you can attach an error handler with
44
+ # `#errback` if you like.
42
45
  #
43
46
  def db_insert(db, tbl, params)
44
47
  db.exec_defer(*insert_sql(tbl, params))
@@ -59,23 +62,27 @@ module PG::EM::Client::Helper
59
62
  # `db_transaction` returns to specify what to run after the transaction
60
63
  # completes successfully or fails, respectively.
61
64
  #
62
- # Arguments:
65
+ # @param db [PG::EM::Client, PG::EM::ConnectionPool] the connection
66
+ # against which the transaction will be executed. If you pass a
67
+ # `ConnectionPool`, we will automatically hold a single connection for
68
+ # the transaction to complete against, so you don't have to worry about
69
+ # that, either.
63
70
  #
64
- # * `db` -- A PG::EM::Client or PG::EM::ConnectionPool instance, against
65
- # which all database operations will be executed. If you pass a
66
- # ConnectionPool, we will automatically hold a single connection for
67
- # the transaction to complete against, so you don't have to worry
68
- # about that, either.
71
+ # @param blk [Proc] code which will be executed within the context of the
72
+ # transaction. This block will be passed a
73
+ # {PG::EM::Client::Helper::Transaction} instance, which has methods to
74
+ # allow you to commit or rollback the transaction, and execute SQL
75
+ # statements within the context of the transaction.
69
76
  #
70
- # * `blk` -- A block of code which will be executed within the context
71
- # of the transaction. This block will be passed a
72
- # `PG::EM::Client::Helper::Transaction` instance, which has methods to
73
- # allow you to commit or rollback the transaction, and execute SQL
74
- # statements within the context of the transaction.
77
+ # @return [EM::Deferrable] on which you can call `#callback` and
78
+ # `#errback` to define what to do when the transaction succeeds or
79
+ # fails, respectively.
75
80
  #
76
- # Returns a deferrable object, on which you can call `#callback` and
77
- # `#errback` to define what to do when the transaction succeeds or fails,
78
- # respectively.
81
+ # @note Due to the way that transactions detect when they are completed,
82
+ # every deferrable in the scope of the transaction must be generated
83
+ # by the transaction. That is, you cannot use objects other than the
84
+ # transaction asynchronously. This is a known limitation, and will be
85
+ # addressed in a future version of this library.
79
86
  #
80
87
  def db_transaction(db, opts = {}, &blk)
81
88
  if db.is_a? PG::EM::ConnectionPool
@@ -91,11 +98,14 @@ module PG::EM::Client::Helper
91
98
  # it so that it will always be valid, no matter what insanity someone's
92
99
  # decided to put in their names.
93
100
  #
101
+ # @param id [String]
102
+ #
103
+ # @return [String] just like `id`, but with added quoting.
104
+ #
94
105
  def quote_identifier(id)
95
106
  "\"#{id.gsub(/"/, '""')}\""
96
107
  end
97
108
  end
98
109
 
99
- require_relative 'em-pg-client-helper/transaction'
100
- require_relative 'em-pg-client-helper/deferrable_group'
101
-
110
+ require 'em-pg-client-helper/transaction'
111
+ require 'em-pg-client-helper/deferrable_group'
@@ -7,23 +7,56 @@
7
7
  class PG::EM::Client::Helper::DeferrableGroup
8
8
  include ::EventMachine::Deferrable
9
9
 
10
+ # Create a new deferrable group.
11
+ #
10
12
  def initialize
11
13
  @failed = false
14
+ @finished = false
12
15
  @first_failure = nil
13
16
  @outstanding = []
14
17
  yield(self) if block_given?
15
18
  end
16
19
 
20
+ # Add a new deferrable to this group.
21
+ #
22
+ # @param df [EM::Deferrable] the deferrable to wait on.
23
+ #
24
+ # @return [EM::Deferrable] the same deferrable.
25
+ #
26
+ # @raise [RuntimeError] if you attempt to add a deferrable after the
27
+ # group has already "completed" (that is, all deferrables that were
28
+ # previously added to the group have finished).
29
+ #
17
30
  def add(df)
31
+ if @finished
32
+ raise RuntimeError,
33
+ "This deferrable group has already completed."
34
+ end
35
+
18
36
  @outstanding << df
19
37
  df.callback { completed(df) }.errback { |ex| failed(df, ex) }
20
38
  end
21
39
 
40
+ # Mark a deferrable as having been completed.
41
+ #
42
+ # If this is the last deferrable in the group, then the callback/errback
43
+ # will be triggered.
44
+ #
45
+ # @param df [EM::Deferrable]
46
+ #
22
47
  def completed(df)
23
48
  @outstanding.delete(df)
24
49
  maybe_done
25
50
  end
26
51
 
52
+ # Register that a given deferrable completed, but has failed.
53
+ #
54
+ # As soon as `failed` has been called, the deferrable group is guaranteed
55
+ # to fail, no matter how many of the deferrables in the group succeed.
56
+ # If this is the first deferrable in the group to have failed, then `ex`
57
+ # will be the exception passed to the `errback`, otherwise the exception
58
+ # will unfortunately be eaten by a grue.
59
+ #
27
60
  def failed(df, ex)
28
61
  @first_failure ||= ex
29
62
  @failed = true
@@ -31,8 +64,11 @@ class PG::EM::Client::Helper::DeferrableGroup
31
64
  end
32
65
 
33
66
  private
67
+ # Called every time a deferrable finishes, just in case we're ready to
68
+ # trigger our callbacks.
34
69
  def maybe_done
35
70
  if @outstanding.empty?
71
+ @finished = true
36
72
  if @failed
37
73
  fail(@first_failure)
38
74
  else
@@ -11,16 +11,21 @@ class PG::EM::Client::Helper::Transaction
11
11
 
12
12
  DeferrableGroup.new do |dg|
13
13
  @dg = dg
14
- dg.add(
15
- conn.exec_defer("BEGIN").callback do
16
- begin
17
- blk.call(self)
18
- rescue StandardError => ex
19
- rollback(ex)
20
- end
21
- end.errback { |ex| rollback(ex) }
22
- )
23
- end.callback { commit }.errback { |ex| rollback(ex) }
14
+
15
+ df = conn.exec_defer("BEGIN").callback do
16
+ begin
17
+ blk.call(self)
18
+ rescue StandardError => ex
19
+ rollback(ex)
20
+ end
21
+ end.errback { |ex| rollback(ex) }
22
+
23
+ @dg.add(df)
24
+ end.callback do
25
+ rollback(RuntimeError.new("txn.commit was not called"))
26
+ end.errback do |ex|
27
+ rollback(ex)
28
+ end
24
29
  end
25
30
 
26
31
  # Signal the database to commit this transaction. You must do this
@@ -31,10 +36,12 @@ class PG::EM::Client::Helper::Transaction
31
36
  #
32
37
  def commit
33
38
  if @active
34
- @conn.exec_defer("COMMIT").callback do
39
+ df = @conn.exec_defer("COMMIT").callback do
35
40
  @active = false
36
41
  self.succeed
37
42
  end.errback { |ex| rollback(ex) }
43
+
44
+ @dg.add(df)
38
45
  end
39
46
  end
40
47
 
@@ -45,10 +52,12 @@ class PG::EM::Client::Helper::Transaction
45
52
  #
46
53
  def rollback(ex)
47
54
  if @active
48
- @conn.exec_defer("ROLLBACK") do
55
+ df = @conn.exec_defer("ROLLBACK") do
49
56
  @active = false
50
57
  self.fail(ex)
51
58
  end
59
+
60
+ @dg.add(df)
52
61
  end
53
62
  end
54
63
 
@@ -70,12 +79,12 @@ class PG::EM::Client::Helper::Transaction
70
79
  def exec(sql, values=[], &blk)
71
80
  unless @active
72
81
  raise RuntimeError,
73
- "Cannot execute a query in a transaction that has been closed"
82
+ "Cannot execute a query in a transaction that has been closed"
74
83
  end
75
84
 
76
85
  @dg.add(
77
86
  @conn.exec_defer(sql, values).
78
- tap { |df| df.callback(&blk) if blk }
87
+ tap { |df| df.callback(&blk) if blk }
79
88
  )
80
89
  end
81
90
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-pg-client-helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
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: 2014-10-26 00:00:00.000000000 Z
12
+ date: 2015-01-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: git-version-bump
@@ -157,6 +157,28 @@ dependencies:
157
157
  version: '0'
158
158
  - !ruby/object:Gem::Dependency
159
159
  name: rake
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: '10.4'
166
+ - - ! '>='
167
+ - !ruby/object:Gem::Version
168
+ version: 1.0.4.2
169
+ type: :development
170
+ prerelease: false
171
+ version_requirements: !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ~>
175
+ - !ruby/object:Gem::Version
176
+ version: '10.4'
177
+ - - ! '>='
178
+ - !ruby/object:Gem::Version
179
+ version: 1.0.4.2
180
+ - !ruby/object:Gem::Dependency
181
+ name: redcarpet
160
182
  requirement: !ruby/object:Gem::Requirement
161
183
  none: false
162
184
  requirements:
@@ -172,7 +194,7 @@ dependencies:
172
194
  - !ruby/object:Gem::Version
173
195
  version: '0'
174
196
  - !ruby/object:Gem::Dependency
175
- name: rdoc
197
+ name: rspec
176
198
  requirement: !ruby/object:Gem::Requirement
177
199
  none: false
178
200
  requirements:
@@ -188,7 +210,7 @@ dependencies:
188
210
  - !ruby/object:Gem::Version
189
211
  version: '0'
190
212
  - !ruby/object:Gem::Dependency
191
- name: rspec
213
+ name: yard
192
214
  requirement: !ruby/object:Gem::Requirement
193
215
  none: false
194
216
  requirements:
@@ -211,6 +233,7 @@ extra_rdoc_files:
211
233
  - README.md
212
234
  files:
213
235
  - .gitignore
236
+ - .yardopts
214
237
  - Gemfile
215
238
  - Guardfile
216
239
  - LICENCE
@@ -238,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
238
261
  version: '0'
239
262
  segments:
240
263
  - 0
241
- hash: -448126625621409328
264
+ hash: 1485031503438797399
242
265
  required_rubygems_version: !ruby/object:Gem::Requirement
243
266
  none: false
244
267
  requirements:
@@ -247,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
270
  version: '0'
248
271
  segments:
249
272
  - 0
250
- hash: -448126625621409328
273
+ hash: 1485031503438797399
251
274
  requirements: []
252
275
  rubyforge_project:
253
276
  rubygems_version: 1.8.23
@@ -255,3 +278,4 @@ signing_key:
255
278
  specification_version: 3
256
279
  summary: Simplify common operations using em-pg-client
257
280
  test_files: []
281
+ has_rdoc: