yiffspace 0.1.7 → 0.1.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 005aad0fa1bb9ee0b93c116a8ff16ee6b9221393b7218ace6458a0a205edf851
4
- data.tar.gz: 3184951a3460ebb9c4b3afc7174f2956789d7a1617b6b6bdf0a8c7567298ab71
3
+ metadata.gz: b8d498d64c506f7f2c008b8c03aca70d0d51f371805cbd1f6c5c4d9fdb89a453
4
+ data.tar.gz: c311ba586f4365538d8a0802ad47ab000ea90a76f94d6b9e0642aef233bfcba2
5
5
  SHA512:
6
- metadata.gz: c3aedc62b4a752a0124e8a41ac8aa013ea5a54cc7f95d5876afda928bcad70e9b13b0744a42cde382dfb2a7d4af3f7d906493971c28f0813d9f24de7ef70fb23
7
- data.tar.gz: 0063344df91e5a741fe752be20b1f591b51df35bbc16746a7eb51d155c16b77c8d39824a7a8f0dc7c2f852444c48fe802b84f00ac9a7ab6e34af08c0489b46bc
6
+ metadata.gz: d463a33bee7f0760dc314e832ad7776a894185ee46590b87f3c49f540a89c521732d28f7b126b6606f03204f013b8230d05d512043130e3b101e2e33e0cf2d68
7
+ data.tar.gz: 561db6abdedb892c69defa2bc2f2baebf4cdf1f79d1ab194ed45ebc3929eaef6121a70dd0cfec2811f10dadc85688b14ea78e95aece7a59352d04ce3d05d2659
@@ -0,0 +1,40 @@
1
+ Description:
2
+ Generates a new one-time fix script tracked by YiffSpace::FixTracker.
3
+
4
+ Example:
5
+ bin/rails generate yiffspace:fixer fixer_name
6
+
7
+ This will create:
8
+ db/fixes/<id>_fixer_name.rb
9
+
10
+ bin/rails generate yiffspace:fixer fixer_name --steps 2
11
+
12
+ This will create:
13
+ db/fixes/<id>_1_fixer_name.rb
14
+ db/fixes/<id>_2_fixer_name.rb
15
+
16
+ A host app can define named templates, auto-discovered from db/fixer_templates/*.rb (see
17
+ YiffSpace::FixerTemplate and YiffSpace.config.fixer_templates_path) - no registration needed,
18
+ just define a subclass. Each `step` block's return value becomes that step's file content:
19
+
20
+ # db/fixer_templates/elasticsearch_template.rb
21
+ class ElasticsearchTemplate < YiffSpace::FixerTemplate
22
+ short("e")
23
+
24
+ step { "# add the elasticsearch index\n" }
25
+ step { "# backfill the elasticsearch data\n" }
26
+ end
27
+
28
+ bin/rails generate yiffspace:fixer fixer_name --template elasticsearch
29
+ bin/rails generate yiffspace:fixer fixer_name -t elasticsearch
30
+ bin/rails generate yiffspace:fixer fixer_name -e
31
+
32
+ All three create the 2 steps above; `short` is optional - a template is always reachable via
33
+ --template/-t, the shortname flag is just a convenience.
34
+
35
+ A host app can also register a preset with just a step count (no per-step content - every
36
+ step falls back to the generic fixer.rb template) directly in an initializer instead:
37
+
38
+ YiffSpace.configure do |config|
39
+ config.fixer_templates.register(:legacy, steps: 3)
40
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yiffspace
4
+ # Scaffolds a new db/fixes/*.rb script for YiffSpace::FixTracker (see `rake fixes:list`).
5
+ #
6
+ # `--steps N` splits the fix into N ordered steps sharing an id, each one a copy of the generic
7
+ # fixer.rb template. A host app can instead define a YiffSpace::FixerTemplate subclass (see that
8
+ # class) to control both the step count and each step's file content, auto-discovered from
9
+ # YiffSpace.config.fixer_templates_path - reachable here with `--template <name>`/`-t <name>`,
10
+ # or with the template's own shortname flag if it registered one (e.g. `-e`).
11
+ class FixerGenerator < Rails::Generators::NamedBase
12
+ source_root(File.expand_path("templates", __dir__))
13
+ # No short alias - -s/-f/-p/-q are already claimed by Rails::Generators::Base's own runtime
14
+ # options (--skip/--force/--pretend/--quiet), and Thor silently lets the last-defined
15
+ # class_option win a collision instead of erroring.
16
+ class_option(:steps, type: :numeric, default: 1,
17
+ desc: "Split the fix into N ordered steps sharing an id, e.g. 12_1_name.rb, 12_2_name.rb")
18
+ class_option(:template, type: :string, default: nil, aliases: ["-t"],
19
+ desc: "Use a fixer template registered with YiffSpace.config.fixer_templates")
20
+
21
+ YiffSpace.config.fixer_templates.each do |template|
22
+ next unless template.short
23
+
24
+ class_option(template.name.to_sym, type: :boolean, default: false, aliases: ["-#{template.short}"],
25
+ desc: "Shortcut for --template #{template.name}")
26
+ end
27
+
28
+ def create_fixer
29
+ content_blocks = resolve_content_blocks
30
+
31
+ id = Dir[File.join(destination_root, "db/fixes/*.rb")].map { |f| File.basename(f, ".rb").split("_").first.to_i }.max.to_i + 1
32
+
33
+ if content_blocks.size == 1
34
+ create_fixer_file("db/fixes/#{id}_#{file_name}.rb", content_blocks.first)
35
+ else
36
+ content_blocks.each_with_index { |block, index| create_fixer_file("db/fixes/#{id}_#{index + 1}_#{file_name}.rb", block) }
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # One entry per step - a block returning that step's file content, or nil to fall back to
43
+ # copying the generic fixer.rb template (a plain --steps N, or a manually
44
+ # YiffSpace.config.fixer_templates.register'd template, has no per-step content).
45
+ def resolve_content_blocks
46
+ template = resolve_template
47
+ return template.content_blocks if template
48
+
49
+ Array.new(steps_from_flag)
50
+ end
51
+
52
+ def resolve_template
53
+ name = template_name
54
+ return nil if name.nil?
55
+
56
+ template = YiffSpace.config.fixer_templates[name]
57
+ raise(Thor::Error, "no fixer template named #{name.inspect} is registered") unless template
58
+
59
+ template
60
+ end
61
+
62
+ # The template chosen via `--template <name>`, or via a registered template's own shortname
63
+ # flag (e.g. `-e` for a template registered with `short: "e"`) - nil if neither was passed.
64
+ def template_name
65
+ return options["template"] if options["template"]
66
+
67
+ YiffSpace.config.fixer_templates.find { |template| template.short && options[template.name] }&.name
68
+ end
69
+
70
+ def steps_from_flag
71
+ steps = options["steps"].to_i
72
+ raise(Thor::Error, "--steps must be at least 1") if steps < 1
73
+
74
+ steps
75
+ end
76
+
77
+ def create_fixer_file(path, content_block)
78
+ if content_block
79
+ create_file(path, content_block.call)
80
+ chmod(path, "+x")
81
+ else
82
+ copy_file("fixer.rb", path, mode: :preserve)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config", "environment")))
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yiffspace
4
+ module Install
5
+ # Installs YiffSpace::FixTracker into a host app: `bin/rails generate yiffspace:install:fixes`
6
+ # copies the `fixes` tracking table migration. Run `bin/rails db:migrate` afterwards.
7
+ class FixesGenerator < Rails::Generators::Base
8
+ include(Rails::Generators::Migration)
9
+
10
+ source_root(File.expand_path("templates", __dir__))
11
+
12
+ def self.next_migration_number(dirname)
13
+ ActiveRecord::Migration.next_migration_number(current_migration_number(dirname) + 1)
14
+ end
15
+
16
+ def create_migration_file
17
+ migration_template("create_fixes.rb.erb", "db/migrate/create_fixes.rb")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tracks which db/fixes/*.rb scripts have been applied, the same way schema_migrations tracks
4
+ # migrations - see YiffSpace::FixTracker and `rake fixes:migrate`/`rake fixes:list`.
5
+ #
6
+ # `id` is the fix's own leading number (e.g. 12, 23), not a surrogate key, so it isn't unique on
7
+ # its own - a fix can be split into ordered sub-steps (12_1, 12_2, ...) that share an id and are
8
+ # distinguished by `index`. `index` is null for fixes with no subtype.
9
+ class CreateFixes < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
10
+ def change
11
+ create_table(:fixes, id: false) do |t|
12
+ t.integer(:id, null: false) # not a surrogate key, this is the fix's own leading number
13
+ t.integer(:index)
14
+ end
15
+
16
+ add_index(:fixes, %i[id index], unique: true, nulls_not_distinct: true)
17
+ end
18
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Keep structure.sql's fixes rows in sync with the database on every schema dump, the same way
4
+ # ActiveRecord keeps schema_migrations rows in sync - not just when `fixes:migrate` runs.
5
+ Rake::Task["db:schema:dump"].enhance do
6
+ YiffSpace::FixTracker.dump_structure_sql!
7
+ end
8
+
9
+ namespace(:fixes) do
10
+ desc("List available fix scripts in db/fixes, marking which have already been applied")
11
+ task(list: :environment) do
12
+ applied = YiffSpace::FixTracker.applied
13
+ YiffSpace::FixTracker.all_fixes.each do |name|
14
+ puts("#{applied.include?(YiffSpace::FixTracker.key_for(name)) ? '[x]' : '[ ]'} #{name}")
15
+ end
16
+ end
17
+
18
+ desc("Run a fix script from db/fixes by id or name, e.g. `rake fixes:run[1]` - re-runs even if already recorded as applied")
19
+ task(:run, [:name] => :environment) do |_task, args|
20
+ name = args[:name].to_s.delete_suffix(".rb")
21
+ abort("Usage: rake fixes:run[id_or_name] (see `rake fixes:list`)") if name.blank?
22
+
23
+ candidates = Dir["db/fixes/*.rb"]
24
+ exact = candidates.find { |path| File.basename(path, ".rb") == name }
25
+ matches = exact ? [exact] : candidates.select { |path| File.basename(path, ".rb").start_with?("#{name}_") || File.basename(path, ".rb").include?(name) }
26
+
27
+ if matches.empty?
28
+ abort("No fix matches \"#{name}\". Run `rake fixes:list` to see available fixes.")
29
+ elsif matches.size > 1
30
+ abort("Multiple fixes match \"#{name}\", be more specific:\n#{matches.map { |m| " #{File.basename(m, '.rb')}" }.join("\n")}")
31
+ end
32
+
33
+ puts("Running #{File.basename(matches.first, '.rb')}...")
34
+ name = YiffSpace::FixTracker.run!(matches.first)
35
+ puts("Recorded #{name} as applied")
36
+ end
37
+
38
+ desc("Apply all fix scripts not yet recorded as applied, in order, then dump the schema like db:migrate does")
39
+ task(migrate: :environment) do
40
+ pending = YiffSpace::FixTracker.pending
41
+
42
+ if pending.empty?
43
+ puts("No pending fixes.")
44
+ else
45
+ pending.each do |name|
46
+ puts("Running #{name}...")
47
+ YiffSpace::FixTracker.run!(YiffSpace::FixTracker.fix_path(name))
48
+ puts("Recorded #{name} as applied")
49
+ end
50
+ end
51
+
52
+ Rake::Task["db:_dump"].invoke
53
+ end
54
+
55
+ desc("Record all of the current fixes as having been applied")
56
+ task(load: :environment) do
57
+ list = YiffSpace::FixTracker.all_fixes.map { YiffSpace::FixTracker.key_for(it) }
58
+ existing = ActiveRecord::Base.connection.select_all('SELECT id, "index" FROM fixes ORDER BY id, "index"').rows
59
+ list.reject! { |id, index| existing.any? { |e| e[0] == id && e[1] == index } }
60
+ unless list.empty?
61
+ values = list.map { |id, index| "(#{id}, #{index.nil? ? 'NULL' : index})" }.join(", ")
62
+ ActiveRecord::Base.connection.execute(%(INSERT INTO fixes (id, "index") VALUES #{values}))
63
+ end
64
+ puts("Loaded #{list.length} #{'fix'.pluralize(list.length)}")
65
+ end
66
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YiffSpace
4
+ class Configuration
5
+ # Named presets for `bin/rails generate yiffspace:fixer`, so `--template <name>` (or a
6
+ # registered shortname flag) can stand in for `--steps N`. Populated two ways:
7
+ #
8
+ # - Automatically, from YiffSpace::FixerTemplate subclasses found in
9
+ # YiffSpace.config.fixer_templates_path (the common case - see FixerTemplate).
10
+ # - Manually, via #register, for a preset that just needs a step count and no per-step
11
+ # content (every step falls back to the generic fixer.rb template).
12
+ #
13
+ # See YiffSpace::Configuration#fixer_templates and Yiffspace::FixerGenerator.
14
+ class FixerTemplates
15
+ include(Enumerable)
16
+
17
+ Template = Struct.new(:name, :short, :content_blocks, keyword_init: true) do
18
+ def steps
19
+ content_blocks.size
20
+ end
21
+ end
22
+
23
+ # -t is yiffspace:fixer's own --template flag; -f/-p/-q/-s are Rails::Generators::Base's
24
+ # built-in runtime options (--force/--pretend/--quiet/--skip).
25
+ RESERVED_SHORTS = %w[t f p q s].freeze
26
+
27
+ def initialize
28
+ @templates = {}
29
+ @discovered = false
30
+ end
31
+
32
+ # short is optional - a template is always reachable via `--template <name>`, a shortname
33
+ # flag (e.g. `-e`) is just a convenient alias for it.
34
+ def register(name, steps:, short: nil)
35
+ raise(ArgumentError, "steps must be a positive integer, got #{steps.inspect}") unless steps.is_a?(Integer) && steps.positive?
36
+
37
+ add(name.to_s, short: short, content_blocks: Array.new(steps))
38
+ end
39
+
40
+ def [](name)
41
+ discover!
42
+ @templates[name.to_s]
43
+ end
44
+
45
+ def each(&)
46
+ discover!
47
+ @templates.each_value(&)
48
+ end
49
+
50
+ private
51
+
52
+ def add(name, short:, content_blocks:)
53
+ raise(ArgumentError, "a fixer template named #{name.inspect} is already registered") if @templates.key?(name)
54
+
55
+ short = short.to_s.delete_prefix("-") if short
56
+ if short
57
+ raise(ArgumentError, "\"-#{short}\" is reserved by yiffspace:fixer's own options") if RESERVED_SHORTS.include?(short)
58
+
59
+ existing = @templates.values.find { |template| template.short == short }
60
+ raise(ArgumentError, "\"-#{short}\" is already registered to the #{existing.name.inspect} fixer template") if existing
61
+ end
62
+
63
+ @templates[name] = Template.new(name: name, short: short, content_blocks: content_blocks)
64
+ end
65
+
66
+ # Scans YiffSpace.config.fixer_templates_path for YiffSpace::FixerTemplate subclasses and
67
+ # registers each one - runs once, the first time a template is looked up (#[] or #each),
68
+ # so it sees whatever the host app registered manually beforehand.
69
+ def discover!
70
+ return if @discovered
71
+
72
+ @discovered = true
73
+ path = YiffSpace.config.fixer_templates_path
74
+ return unless path && Dir.exist?(path)
75
+
76
+ before = FixerTemplate.subclasses
77
+ Dir[File.join(path, "*.rb")].each { |file| require(file) }
78
+
79
+ (FixerTemplate.subclasses - before).each do |klass|
80
+ raise(ArgumentError, "#{klass.name} has no step blocks - add at least one `step { ... }`") if klass.steps.empty?
81
+
82
+ add(klass.template_name, short: klass.short, content_blocks: klass.steps)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -112,5 +112,19 @@ module YiffSpace
112
112
  def images
113
113
  @images ||= Images.new
114
114
  end
115
+
116
+ # Named `--steps` presets for `bin/rails generate yiffspace:fixer`. See
117
+ # YiffSpace::Configuration::FixerTemplates.
118
+ def fixer_templates
119
+ @fixer_templates ||= FixerTemplates.new
120
+ end
121
+
122
+ # Directory scanned for YiffSpace::FixerTemplate subclasses (see FixerTemplate) - defaults to
123
+ # db/fixer_templates in the host app.
124
+ attr_writer(:fixer_templates_path)
125
+
126
+ def fixer_templates_path
127
+ @fixer_templates_path ||= Rails.root.join("db/fixer_templates")
128
+ end
115
129
  end
116
130
  end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YiffSpace
4
+ # Tracks which db/fixes/*.rb scripts a host app has applied, in a `fixes` table (see
5
+ # db/migrate/*_create_fixes.rb) the same way ActiveRecord's own schema_migrations table
6
+ # tracks migrations. Used by the `fixes:*` rake tasks (lib/tasks/fixes.rake).
7
+ module FixTracker
8
+ module_function
9
+
10
+ def fix_path(name)
11
+ Rails.root.glob("db/fixes/#{name}.rb").first
12
+ end
13
+
14
+ # db/fixes filenames are "<id>_description.rb", occasionally "<id>_<index>_description.rb"
15
+ # (e.g. 1_1_..., 1_2_...) for a handful of fixes split into ordered steps - the `fixes`
16
+ # table mirrors this as an (id, index) pair, with index null for fixes with no subtype.
17
+ def key_for(name)
18
+ id, maybe_index = name.split("_", 3)
19
+ index = maybe_index =~ /\A\d+\z/ ? maybe_index.to_i : nil
20
+ [id.to_i, index]
21
+ end
22
+
23
+ # Sort on the (id, index) parts, not the filename string, so 12 doesn't sort before 2_2.
24
+ def sort_key(name)
25
+ id, index = key_for(name)
26
+ [id, index || 0]
27
+ end
28
+
29
+ # Only numbered one-time fixes are tracked/auto-applied - a host app's db/fixes may also hold
30
+ # reusable on-demand maintenance scripts that aren't meant to run automatically as part of
31
+ # `fixes:migrate`. Those stay reachable via `fixes:run[name]`.
32
+ def all_fixes
33
+ Rails.root.glob("db/fixes/*.rb").map { |path| File.basename(path, ".rb") }.grep(/\A\d/).sort_by { |name| sort_key(name) }
34
+ end
35
+
36
+ def applied
37
+ ActiveRecord::Base.connection.select_rows('SELECT id, "index" FROM fixes').to_set
38
+ end
39
+
40
+ def applied?(name)
41
+ id, index = key_for(name)
42
+ conn = ActiveRecord::Base.connection
43
+ index_clause = index.nil? ? '"index" IS NULL' : %("index" = #{index})
44
+ conn.select_value("SELECT 1 FROM fixes WHERE id = #{id} AND #{index_clause}").present?
45
+ end
46
+
47
+ def pending
48
+ applied_keys = applied
49
+ all_fixes.reject { |name| applied_keys.include?(key_for(name)) }
50
+ end
51
+
52
+ def record!(name)
53
+ id, index = key_for(name)
54
+ conn = ActiveRecord::Base.connection
55
+ conn.execute(<<~SQL.squish)
56
+ INSERT INTO fixes (id, "index") VALUES (#{id}, #{index || 'NULL'})
57
+ ON CONFLICT (id, "index") DO NOTHING
58
+ SQL
59
+ end
60
+
61
+ def run!(path)
62
+ name = File.basename(path, ".rb")
63
+ load(File.expand_path(path))
64
+ record!(name)
65
+ name
66
+ end
67
+
68
+ # Mirrors how ActiveRecord appends `INSERT INTO "schema_migrations"` to structure.sql after
69
+ # a schema dump (see Connection#dump_schema_versions) - appends the currently-applied fixes
70
+ # the same way, so loading structure.sql into a fresh database marks them applied too instead
71
+ # of leaving `fixes:migrate` to re-run every historical fix. Hooked into `db:schema:dump` in
72
+ # lib/tasks/fixes.rake, so it runs on every schema dump, not just `fixes:migrate`.
73
+ def dump_structure_sql!
74
+ db_config = ActiveRecord::Base.connection_db_config
75
+ return unless db_config.schema_format == :sql
76
+
77
+ filename = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(db_config)
78
+ return unless filename && File.exist?(filename)
79
+
80
+ conn = ActiveRecord::Base.connection
81
+ return unless conn.table_exists?(:fixes)
82
+
83
+ rows = conn.select_rows('SELECT id, "index" FROM fixes ORDER BY id DESC, "index" DESC NULLS LAST')
84
+ return if rows.empty?
85
+
86
+ values = rows.map { |id, index| "(#{id}, #{index || 'NULL'})" }.join(",\n")
87
+ File.open(filename, "a") do |f|
88
+ f.puts(<<~TEXT)
89
+ INSERT INTO "fixes" (id, "index") VALUES
90
+ #{values};
91
+ TEXT
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YiffSpace
4
+ # Base class for a `bin/rails generate yiffspace:fixer` template, auto-discovered from *.rb
5
+ # files in YiffSpace.config.fixer_templates_path (default db/fixer_templates) - no explicit
6
+ # registration needed, just define a subclass:
7
+ #
8
+ # class ElasticsearchTemplate < YiffSpace::FixerTemplate
9
+ # short("e")
10
+ #
11
+ # step { "..." }
12
+ # step { "..." }
13
+ # end
14
+ #
15
+ # The template's name comes from the class name with a trailing "Template" dropped and
16
+ # kebab-cased (ElasticsearchTemplate -> "elasticsearch", OpenSearchTemplate -> "open-search"),
17
+ # reachable as `--template <name>` (see Yiffspace::FixerGenerator). Its step count is the
18
+ # number of `step` blocks - each one's return value becomes that step's fix file content,
19
+ # instead of the generic fixer.rb template a plain `--steps N` copies for every step.
20
+ class FixerTemplate
21
+ class << self
22
+ # Optional - a template is always reachable via `--template <name>`, a registered
23
+ # shortname flag (e.g. `-e`) is just a convenient alias for it.
24
+ def short(value = nil)
25
+ @short = value.to_s.delete_prefix("-") unless value.nil?
26
+ @short
27
+ end
28
+
29
+ def step(&block)
30
+ raise(ArgumentError, "#{name}.step requires a block") unless block
31
+
32
+ steps << block
33
+ end
34
+
35
+ def steps
36
+ @steps ||= []
37
+ end
38
+
39
+ def template_name
40
+ name.demodulize.delete_suffix("Template").underscore.dasherize
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YiffSpace
4
- VERSION = "0.1.7"
4
+ VERSION = "0.1.8"
5
5
  end
data/lib/yiffspace.rb CHANGED
@@ -21,6 +21,7 @@ loader.inflector.inflect({ "postgresql" => "PostgreSQL", "yiffspace" => "YiffSpa
21
21
  loader.ignore("#{__dir__}/yiffspace/core_ext")
22
22
  loader.ignore("#{__dir__}/yiffspace/include")
23
23
  loader.ignore("#{__dir__}/yiffspace/engine.rb")
24
+ loader.ignore("#{__dir__}/generators")
24
25
  loader.setup
25
26
 
26
27
  # Require the engine eagerly so it registers with Rails before the host app's
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yiffspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Donovan_DMC
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-08-21 00:00:00.000000000 Z
10
+ date: 2026-08-22 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: abbrev
@@ -97,6 +97,12 @@ files:
97
97
  - app/models/yiff_space/application_record.rb
98
98
  - app/views/layouts/yiff_space/application.html.erb
99
99
  - app/views/yiff_space/error.html.erb
100
+ - lib/generators/yiffspace/fixer/USAGE
101
+ - lib/generators/yiffspace/fixer/fixer_generator.rb
102
+ - lib/generators/yiffspace/fixer/templates/fixer.rb
103
+ - lib/generators/yiffspace/install/fixes_generator.rb
104
+ - lib/generators/yiffspace/install/templates/create_fixes.rb.erb
105
+ - lib/tasks/fixes.rake
100
106
  - lib/yiffspace.rb
101
107
  - lib/yiffspace/concerns/active_record_extensions.rb
102
108
  - lib/yiffspace/concerns/api_methods.rb
@@ -112,6 +118,7 @@ files:
112
118
  - lib/yiffspace/concerns/user_resolvable_methods.rb
113
119
  - lib/yiffspace/config_builder.rb
114
120
  - lib/yiffspace/configuration.rb
121
+ - lib/yiffspace/configuration/fixer_templates.rb
115
122
  - lib/yiffspace/configuration/images.rb
116
123
  - lib/yiffspace/core_ext/active_record/all.rb
117
124
  - lib/yiffspace/core_ext/active_record/cross_join_lateral.rb
@@ -151,6 +158,8 @@ files:
151
158
  - lib/yiffspace/extensions/object/to_b.rb
152
159
  - lib/yiffspace/extensions/object/truthy_falsy.rb
153
160
  - lib/yiffspace/extensions/string/sql.rb
161
+ - lib/yiffspace/fix_tracker.rb
162
+ - lib/yiffspace/fixer_template.rb
154
163
  - lib/yiffspace/images.rb
155
164
  - lib/yiffspace/images/avatar.rb
156
165
  - lib/yiffspace/images/avatar/base.rb