em-pg-client-helper 0.3.1 → 0.3.2

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/.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: