constable-rails 0.1.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +277 -1
- data/README.md +174 -13
- data/lib/constable/case.rb +33 -0
- data/lib/constable/cli.rb +90 -5
- data/lib/constable/cold_case/rspec.rb +93 -1
- data/lib/constable/config.rb +95 -8
- data/lib/constable/identity.rb +19 -0
- data/lib/constable/importer/modernizer.rb +40 -0
- data/lib/constable/investigation.rb +10 -0
- data/lib/constable/jail.rb +72 -7
- data/lib/constable/matchers.rb +206 -2
- data/lib/constable/registry.rb +24 -0
- data/lib/constable/reporter.rb +232 -3
- data/lib/constable/runner.rb +153 -3
- data/lib/constable/selection.rb +23 -1
- data/lib/constable/storage/sqlite_adapter.rb +21 -1
- data/lib/constable/version.rb +1 -1
- data/lib/constable/warrants.rb +56 -5
- data/lib/constable/worker_databases.rb +83 -0
- data/lib/constable.rb +48 -1
- data/lib/generators/constable/install_generator.rb +140 -9
- data/lib/generators/constable/templates/case_helper.rb.tt +77 -23
- data/lib/generators/constable/templates/config.yml.tt +32 -7
- metadata +4 -3
|
@@ -19,6 +19,7 @@ module Constable
|
|
|
19
19
|
# test/cases/example_case.rb a worked case so `constable test` does something
|
|
20
20
|
# .constable/config.yml every setting, at its default, as a reference
|
|
21
21
|
# .rubocop.yml the linter, merged into yours if you have one
|
|
22
|
+
# .gitignore two lines, so the blotter stays local
|
|
22
23
|
#
|
|
23
24
|
# Plus the optional :cold_case Gemfile group, but only when there is actually
|
|
24
25
|
# an RSpec or Minitest suite in the repo to import. Installing the gem into a
|
|
@@ -44,18 +45,44 @@ module Constable
|
|
|
44
45
|
desc: "Don't write the example case under test/cases/"
|
|
45
46
|
class_option :skip_support, type: :boolean, default: false,
|
|
46
47
|
desc: "Don't write the example files under test/support/"
|
|
48
|
+
class_option :skip_config, type: :boolean, default: false,
|
|
49
|
+
desc: "Don't write .constable/config.yml -- configure in Ruby instead"
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
COLD_CASE_HEADER = <<~RUBY
|
|
49
52
|
# Cold cases: your existing RSpec/Minitest files, run verbatim through their own
|
|
50
53
|
# real engine, with results merged into Constable's reporting and CI gate. These
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
group :cold_case do
|
|
54
|
-
gem "rspec-rails"
|
|
55
|
-
gem "minitest"
|
|
56
|
-
end
|
|
54
|
+
# gems are needed only for as long as cold cases exist -- delete the group once
|
|
55
|
+
# the suite is fully modernized and the dependencies drop out with it.
|
|
57
56
|
RUBY
|
|
58
57
|
|
|
58
|
+
# Only the engines this repo actually has files for, and only ones the Gemfile does
|
|
59
|
+
# not already declare. An app adopting Constable *from RSpec* -- which is most of
|
|
60
|
+
# them -- already has rspec-rails, and declaring it twice is not a style question:
|
|
61
|
+
# Bundler refuses to parse the file at all, so the install leaves the app unbootable.
|
|
62
|
+
COLD_CASE_GEMS = { rspec: "rspec-rails", minitest: "minitest" }.freeze
|
|
63
|
+
|
|
64
|
+
# Per engine, so a repo with only RSpec files does not get minitest added to its
|
|
65
|
+
# Gemfile for a migration it is never going to do.
|
|
66
|
+
LEGACY_GLOBS = { rspec: "spec/**/*_spec.rb", minitest: "test/**/*_test.rb" }.freeze
|
|
67
|
+
|
|
68
|
+
# The blotter is machine state: this laptop's flake history and jail docket. Sharing
|
|
69
|
+
# it through git would hand CI somebody else's docket and conflict on every run.
|
|
70
|
+
GITIGNORE_ENTRY = <<~TEXT
|
|
71
|
+
# Constable's blotter -- flake history, the jail docket, warrants. Local state:
|
|
72
|
+
# each machine keeps its own, and CI starts clean.
|
|
73
|
+
/.constable/*.sqlite3
|
|
74
|
+
/.constable/*.sqlite3-*
|
|
75
|
+
TEXT
|
|
76
|
+
|
|
77
|
+
NEW_SETTINGS_HEADER = <<~TEXT
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
# Added by `rails generate constable:install` on a later upgrade. These settings
|
|
80
|
+
# did not exist when this file was written; each is shown at its default, so
|
|
81
|
+
# deleting any of them changes nothing.
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
TEXT
|
|
85
|
+
|
|
59
86
|
RUBOCOP_EXTENSION = "rubocop-constable"
|
|
60
87
|
|
|
61
88
|
def create_case_helper
|
|
@@ -69,8 +96,32 @@ module Constable
|
|
|
69
96
|
template "authenticatable.rb.tt", "test/support/authenticatable.rb"
|
|
70
97
|
end
|
|
71
98
|
|
|
99
|
+
# The config file doubles as the reference -- every key at its default, with the
|
|
100
|
+
# reasoning above it -- which only works if it stays current. A gem upgrade cannot
|
|
101
|
+
# rewrite it (that would clobber your settings) and Thor's only other answer is to
|
|
102
|
+
# skip the file entirely, so before 1.1.0 a setting added after you installed was
|
|
103
|
+
# invisible: `output` shipped in 1.0.0 and never appeared in an existing config.
|
|
104
|
+
#
|
|
105
|
+
# So: create it if it is missing, and otherwise append only the settings it does not
|
|
106
|
+
# already mention. Your edits and comments are never touched.
|
|
72
107
|
def create_config
|
|
73
|
-
|
|
108
|
+
if options[:skip_config]
|
|
109
|
+
say_status :skip, ".constable/config.yml (configure in test/case_helper.rb instead)", :blue
|
|
110
|
+
return
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
path = File.join(destination_root, ".constable/config.yml")
|
|
114
|
+
return template("config.yml.tt", ".constable/config.yml") unless File.exist?(path)
|
|
115
|
+
|
|
116
|
+
missing = missing_config_blocks(File.read(path))
|
|
117
|
+
if missing.empty?
|
|
118
|
+
say_status :identical, ".constable/config.yml (every setting is documented)", :blue
|
|
119
|
+
return
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
names = missing.flat_map { |block| config_keys_in(block) }
|
|
123
|
+
say_status :append, ".constable/config.yml (#{names.join(", ")})", :green
|
|
124
|
+
append_to_file ".constable/config.yml", "\n#{NEW_SETTINGS_HEADER}#{missing.join("\n\n")}\n"
|
|
74
125
|
end
|
|
75
126
|
|
|
76
127
|
def create_example_case
|
|
@@ -101,7 +152,31 @@ module Constable
|
|
|
101
152
|
return
|
|
102
153
|
end
|
|
103
154
|
|
|
104
|
-
|
|
155
|
+
gems = cold_case_gems_to_add
|
|
156
|
+
if gems.empty?
|
|
157
|
+
say_status :skip, "Gemfile (every cold-case engine is already declared)", :blue
|
|
158
|
+
return
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
append_to_file "Gemfile", "\n#{cold_case_group(gems)}"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# The blotter must not be committed. Appended rather than templated, because an app
|
|
165
|
+
# always has a .gitignore already and ours is two lines of it.
|
|
166
|
+
def ignore_the_blotter
|
|
167
|
+
path = File.join(destination_root, ".gitignore")
|
|
168
|
+
|
|
169
|
+
unless File.exist?(path)
|
|
170
|
+
create_file ".gitignore", GITIGNORE_ENTRY
|
|
171
|
+
return
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
if File.read(path).include?("/.constable/*.sqlite3")
|
|
175
|
+
say_status :identical, ".gitignore (blotter already ignored)", :blue
|
|
176
|
+
return
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
append_to_file ".gitignore", "\n#{GITIGNORE_ENTRY}"
|
|
105
180
|
end
|
|
106
181
|
|
|
107
182
|
# An app that already lints has opinions in .rubocop.yml worth more than
|
|
@@ -137,6 +212,58 @@ module Constable
|
|
|
137
212
|
|
|
138
213
|
private
|
|
139
214
|
|
|
215
|
+
# An engine earns a line only if this repo has files for it and the Gemfile does not
|
|
216
|
+
# already declare it.
|
|
217
|
+
def cold_case_gems_to_add
|
|
218
|
+
COLD_CASE_GEMS.filter_map do |engine, gem_name|
|
|
219
|
+
next unless legacy_files?(engine)
|
|
220
|
+
next if gem_declared?(gem_name)
|
|
221
|
+
|
|
222
|
+
gem_name
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def cold_case_group(gems)
|
|
227
|
+
lines = gems.map { |gem_name| %( gem "#{gem_name}") }
|
|
228
|
+
"#{COLD_CASE_HEADER}group :cold_case do\n#{lines.join("\n")}\nend\n"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Matches `gem "rspec-rails"` and `gem 'rspec-rails', "~> 8.0"` alike, and ignores a
|
|
232
|
+
# commented-out line, which is a suggestion rather than a declaration.
|
|
233
|
+
def gem_declared?(gem_name)
|
|
234
|
+
gemfile_contents.each_line.any? do |line|
|
|
235
|
+
stripped = line.strip
|
|
236
|
+
next false if stripped.start_with?("#")
|
|
237
|
+
|
|
238
|
+
stripped.match?(/\Agem\s+["']#{Regexp.escape(gem_name)}["']/)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Blocks in the shipped reference whose settings the existing file never mentions.
|
|
243
|
+
# A "block" is a run of lines between blank ones: the comment and the setting it
|
|
244
|
+
# explains travel together, because a bare key with no reasoning is not a reference.
|
|
245
|
+
def missing_config_blocks(existing)
|
|
246
|
+
present = config_keys_in(existing)
|
|
247
|
+
|
|
248
|
+
reference_blocks.select do |block|
|
|
249
|
+
keys = config_keys_in(block)
|
|
250
|
+
keys.any? && (keys - present) == keys
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def reference_blocks
|
|
255
|
+
File.read(find_in_source_paths("config.yml.tt")).split(/\n{2,}/).map(&:rstrip).reject(&:empty?)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Top-level YAML keys only, ignoring comments and nested ones -- a commented-out
|
|
259
|
+
# example is a suggestion, not a declaration.
|
|
260
|
+
def config_keys_in(text)
|
|
261
|
+
text.lines.filter_map do |line|
|
|
262
|
+
match = line.match(/\A([a-z][a-z0-9_]*):/)
|
|
263
|
+
match && match[1]
|
|
264
|
+
end.uniq
|
|
265
|
+
end
|
|
266
|
+
|
|
140
267
|
def gemfile_contents
|
|
141
268
|
File.read(File.join(destination_root, "Gemfile"))
|
|
142
269
|
end
|
|
@@ -148,6 +275,10 @@ module Constable
|
|
|
148
275
|
Dir.glob(File.join(destination_root, "{spec,test}/**/*_{spec,test}.rb")).any?
|
|
149
276
|
end
|
|
150
277
|
|
|
278
|
+
def legacy_files?(engine)
|
|
279
|
+
Dir.glob(File.join(destination_root, LEGACY_GLOBS.fetch(engine))).any?
|
|
280
|
+
end
|
|
281
|
+
|
|
151
282
|
# A textual merge, not a YAML round trip: parsing and re-emitting someone's
|
|
152
283
|
# .rubocop.yml would silently eat every comment in it, and comments in a
|
|
153
284
|
# lint config are usually the reason a rule is there at all.
|
|
@@ -67,9 +67,37 @@ end
|
|
|
67
67
|
# reimplementation of them would be a slightly wrong one.
|
|
68
68
|
# -----------------------------------------------------------------------------
|
|
69
69
|
|
|
70
|
+
# -----------------------------------------------------------------------------
|
|
71
|
+
# Support files -- shared modules and custom matchers.
|
|
72
|
+
#
|
|
73
|
+
# Same role RSpec's spec/support/**/*.rb plays. Shared behavior *across* files
|
|
74
|
+
# is a plain module you `include`; there is deliberately no shared-examples DSL
|
|
75
|
+
# here, because Ruby's own composition tools already do that job with fewer
|
|
76
|
+
# rules to learn and more flexibility once the reuse stops being simple.
|
|
77
|
+
#
|
|
78
|
+
# Sorted on purpose: Dir[] returns filesystem order, which differs between your
|
|
79
|
+
# laptop and CI. A suite that loads its own support files in an unpredictable
|
|
80
|
+
# order has already lost the argument about determinism.
|
|
81
|
+
#
|
|
82
|
+
# Loaded BEFORE the tier classes below, so `include Authenticatable` on a tier
|
|
83
|
+
# is a thing you can actually write. Loading them afterwards would make the
|
|
84
|
+
# advice in test/support/authenticatable.rb raise NameError.
|
|
85
|
+
# -----------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
Dir[Rails.root.join("test/support/**/*.rb")].sort.each { |f| require f }
|
|
88
|
+
|
|
89
|
+
# Factories, when the app has them. `create(:user)` is what a converted spec will be
|
|
90
|
+
# full of, and a NoMethodError on the first native run is a bad way to learn that the
|
|
91
|
+
# include was missing. Guarded, so a suite with no factory gem is unaffected.
|
|
92
|
+
module CaseFactories
|
|
93
|
+
include FactoryBot::Syntax::Methods if defined?(FactoryBot::Syntax::Methods)
|
|
94
|
+
end
|
|
95
|
+
|
|
70
96
|
# No database, no request stack, no browser -- just Ruby. The fastest thing
|
|
71
97
|
# Constable can run, and where most of a suite should live.
|
|
72
98
|
class UnitCase < Constable::Case
|
|
99
|
+
include CaseFactories
|
|
100
|
+
|
|
73
101
|
tier :unit
|
|
74
102
|
end
|
|
75
103
|
|
|
@@ -78,6 +106,12 @@ end
|
|
|
78
106
|
# investigation runs inside a transaction that is rolled back afterwards.
|
|
79
107
|
class IntegrationCase < Constable::Case
|
|
80
108
|
include Constable::RailsSupport::Integration
|
|
109
|
+
include CaseFactories
|
|
110
|
+
|
|
111
|
+
# Every integration case gets the app's sign-in helpers. Uncomment once
|
|
112
|
+
# test/support/authenticatable.rb says something true about your app:
|
|
113
|
+
#
|
|
114
|
+
# include Authenticatable
|
|
81
115
|
|
|
82
116
|
tier :integration
|
|
83
117
|
end
|
|
@@ -87,6 +121,8 @@ end
|
|
|
87
121
|
# and Rails' own `driven_by`. There is no `response` here -- a system case looks
|
|
88
122
|
# at the rendered page, which is the whole reason to pay for a browser.
|
|
89
123
|
class SystemCase < Constable::Case
|
|
124
|
+
include CaseFactories
|
|
125
|
+
|
|
90
126
|
# Capybara is not a Constable dependency. System cases are opt-in, and a suite
|
|
91
127
|
# with no browser tests shouldn't be made to install a browser driver to boot.
|
|
92
128
|
include Constable::RailsSupport::System if defined?(Capybara)
|
|
@@ -100,34 +136,52 @@ class SystemCase < Constable::Case
|
|
|
100
136
|
end
|
|
101
137
|
|
|
102
138
|
# -----------------------------------------------------------------------------
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
# Same role RSpec's spec/support/**/*.rb plays. Shared behavior *across* files
|
|
106
|
-
# is a plain module you `include`; there is deliberately no shared-examples DSL
|
|
107
|
-
# here, because Ruby's own composition tools already do that job with fewer
|
|
108
|
-
# rules to learn and more flexibility once the reuse stops being simple.
|
|
109
|
-
#
|
|
110
|
-
# Sorted on purpose: Dir[] returns filesystem order, which differs between your
|
|
111
|
-
# laptop and CI. A suite that loads its own support files in an unpredictable
|
|
112
|
-
# order has already lost the argument about determinism.
|
|
139
|
+
# Code-level configuration.
|
|
113
140
|
# -----------------------------------------------------------------------------
|
|
114
141
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
#
|
|
118
|
-
#
|
|
142
|
+
# Code only, by default: matchers and suite hooks can be written nowhere else.
|
|
143
|
+
#
|
|
144
|
+
# Settings can be written here too, and this file wins over
|
|
145
|
+
# .constable/config.yml -- a CLI flag wins over both, for one run. Use the file
|
|
146
|
+
# for values that differ per project or per branch, where being greppable
|
|
147
|
+
# without running anything is worth something. Use Ruby when the value has to be
|
|
148
|
+
# computed, which YAML cannot do:
|
|
149
|
+
#
|
|
150
|
+
# c.parallel_workers = ENV.fetch("CI_WORKERS", 4).to_i
|
|
151
|
+
# c.coverage = ENV["CI"] == "true"
|
|
152
|
+
#
|
|
153
|
+
# Every setting, at its default -- uncomment what you want and delete the rest.
|
|
154
|
+
# `.constable/config.yml` explains each one at length and is optional; between
|
|
155
|
+
# the two, this file can be the only place you configure Constable.
|
|
156
|
+
#
|
|
157
|
+
# c.cold_cases = [] # RSpec/Minitest globs to run as cold cases
|
|
158
|
+
# c.parallel_workers = "auto" # or an integer. Each worker gets its own database
|
|
159
|
+
# c.output = :concise # or :expanded -- a line per test, with timings
|
|
160
|
+
# c.fail_on_warnings = false # CI: fail when the warning count is not trending down
|
|
161
|
+
# c.warrants = false # rerun a failure in isolation before believing it
|
|
162
|
+
# c.warrant_retries = 5
|
|
163
|
+
# c.parole_period = 10 # clean runs before a paroled test releases itself
|
|
164
|
+
# c.auto_relink = false # auto-confirm rename detection
|
|
165
|
+
# c.coverage = false
|
|
166
|
+
# c.coverage_threshold = 90 # diff-based: only lines changed in this diff
|
|
167
|
+
# c.coverage_html = false
|
|
168
|
+
# c.tiers = { "unit" => "test/cases/models/**/*" }
|
|
169
|
+
#
|
|
170
|
+
# `storage` is the one setting that cannot go here: the blotter is opened before
|
|
171
|
+
# this file loads, so `constable jail` and `constable status` can read the docket
|
|
172
|
+
# without booting the app. Setting it here raises rather than being ignored. Use
|
|
173
|
+
# .constable/config.yml, or CONSTABLE_STORAGE_URL / _PATH / _ADAPTER.
|
|
174
|
+
#
|
|
175
|
+
# Not config/initializers/: initializers run on every boot including production,
|
|
176
|
+
# where a test-only gem is not in the bundle. Same reason RSpec, SimpleCov and
|
|
177
|
+
# WebMock all configure from the test helper rather than an initializer.
|
|
119
178
|
# -----------------------------------------------------------------------------
|
|
120
179
|
|
|
121
180
|
Constable.configure do |c|
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
# One-time global setup, run once per process before the whole suite. This is
|
|
128
|
-
# for configuring the world -- drivers, adapters, formats -- and deliberately
|
|
129
|
-
# not for creating records that tests then share. See the note at the bottom
|
|
130
|
-
# of this file about why that distinction is the whole ballgame.
|
|
181
|
+
# One-time global setup, run once per process before the whole suite. For
|
|
182
|
+
# configuring the world -- drivers, adapters, formats -- and deliberately not
|
|
183
|
+
# for creating records that tests then share. See the note at the bottom of
|
|
184
|
+
# this file about why that distinction is the whole ballgame.
|
|
131
185
|
#
|
|
132
186
|
# c.before_suite do
|
|
133
187
|
# Capybara.default_driver = :rack_test
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
# .constable/config.yml
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
# anything that is Ruby -- custom matchers, tier base classes, one-time global
|
|
5
|
-
# setup -- lives in test/case_helper.rb instead.
|
|
3
|
+
# Optional. Everything here can also be written in Ruby, in test/case_helper.rb:
|
|
6
4
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
5
|
+
# Constable.configure do |c|
|
|
6
|
+
# c.parallel_workers = ENV.fetch("CI_WORKERS", 4).to_i
|
|
7
|
+
# c.output = :expanded
|
|
8
|
+
# end
|
|
9
|
+
#
|
|
10
|
+
# ...which is the better home for anything computed, and the more familiar one if you
|
|
11
|
+
# come from RSpec's spec_helper.rb. Ruby wins over this file; a CLI flag wins over both.
|
|
12
|
+
#
|
|
13
|
+
# Two reasons this file exists at all:
|
|
14
|
+
#
|
|
15
|
+
# 1. `storage` cannot go anywhere else. The blotter is opened before case_helper.rb
|
|
16
|
+
# loads, so that `constable jail`, `warrants`, `watchlist` and `status` can read the
|
|
17
|
+
# docket without booting the app -- a broken app should not stop you reading the
|
|
18
|
+
# docket. Setting it in Ruby raises rather than being quietly ignored.
|
|
19
|
+
#
|
|
20
|
+
# 2. A settings file is greppable and diffable without executing anything, which is
|
|
21
|
+
# what you want for the values that differ per project or per branch.
|
|
22
|
+
#
|
|
23
|
+
# Every key Constable understands is below at its default, so this doubles as the
|
|
24
|
+
# reference. Delete anything you have not changed; the behavior is identical either way.
|
|
25
|
+
# Re-run `rails generate constable:install --skip` after upgrading and any settings added
|
|
26
|
+
# since will be appended here, leaving your own values and comments alone.
|
|
11
27
|
|
|
12
28
|
# Glob paths to run as cold cases: original RSpec/Minitest files, driven verbatim
|
|
13
29
|
# through their own real engine, with pass/fail/timing fed into Constable's
|
|
@@ -57,6 +73,15 @@ fail_on_warnings: false # CI: fail the build when the warning count doesn't tre
|
|
|
57
73
|
|
|
58
74
|
parallel_workers: auto # or an explicit integer
|
|
59
75
|
|
|
76
|
+
# How much the live stream says while the suite is running. The summary is identical
|
|
77
|
+
# either way -- this only changes what you watch on the way there.
|
|
78
|
+
#
|
|
79
|
+
# concise one glyph per test, grouped into a run per case. A thousand tests stay
|
|
80
|
+
# inside one screen, and a wall of green is the point.
|
|
81
|
+
# expanded a line per test: glyph, name, duration. Slower to read in bulk, but you
|
|
82
|
+
# can see which test is hanging while it hangs, rather than after.
|
|
83
|
+
output: concise # concise | expanded
|
|
84
|
+
|
|
60
85
|
# Fallback path-based tier inference, used only when a case doesn't inherit from
|
|
61
86
|
# a tiered base class. The base classes in test/case_helper.rb are the primary
|
|
62
87
|
# mechanism and always win -- this is here so an un-migrated file still lands in
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: constable-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ray Hughes
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -96,7 +96,7 @@ description: |
|
|
|
96
96
|
The gem is published as "constable-rails"; everything inside it -- the module, the
|
|
97
97
|
CLI, the config directory -- is simply "constable".
|
|
98
98
|
email:
|
|
99
|
-
-
|
|
99
|
+
- raymond.hughes@live.com
|
|
100
100
|
executables:
|
|
101
101
|
- constable
|
|
102
102
|
extensions: []
|
|
@@ -141,6 +141,7 @@ files:
|
|
|
141
141
|
- lib/constable/storage/sqlite_adapter.rb
|
|
142
142
|
- lib/constable/version.rb
|
|
143
143
|
- lib/constable/warrants.rb
|
|
144
|
+
- lib/constable/worker_databases.rb
|
|
144
145
|
- lib/generators/constable/base.rb
|
|
145
146
|
- lib/generators/constable/channel/channel_generator.rb
|
|
146
147
|
- lib/generators/constable/channel/templates/channel_case.rb.tt
|