static_db 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21a5a8909bd4d182d4045ce780e15d9d33c2a2e226148e76928ef76391b6c465
4
- data.tar.gz: 901c8f63945110038f237f562150106d167c2eb6033ec17cf82e60eda97df89a
3
+ metadata.gz: 64c3b151a70d3b1f03bff857579e371b3799548a74980816aef917015bf610b1
4
+ data.tar.gz: f8b63e280ed3fae3191a7c1a57153741d678eb73bfa37a2319d56f43e0ff72c3
5
5
  SHA512:
6
- metadata.gz: 6ff8c6ac84a7a469918dfe1781b4aa94fee65fb81a7bda3f858f11e5be4b7681da9913d7e502bcf8f25270f1f7bf60fdda5a95a8b93a9d861a1eb17bd0dbf8c4
7
- data.tar.gz: befb42dbc227cac64482b9dfcd966c0f0f53754ccb3d71eff0893791c2fe3889f544c674d45a4c97c563026196e6ff2c9da28f2ceb1611bc72fb9afca79362b0
6
+ metadata.gz: 3e9325d80ee2538813a45d5cde76d3753e04a30bbecc6b38289677a150fb9e5226e0f60ac557c0b76288c05e8c922e570ffd7a3c90463cafcbbb3e7869e723c5
7
+ data.tar.gz: cde86cba01f3f3341a66b4469e9733186c0ed710158edcb9197c9885156949e2ca8653ab306f7db583b0257c0d1631f9946e96931d6ea7e02a27055cc32fba3d
data/CHANGELOG.md CHANGED
@@ -12,6 +12,30 @@ This project adheres to [Break Versioning](https://www.taoensso.com/break-versio
12
12
 
13
13
  -
14
14
 
15
+ ## [0.2.0] - 2026-05-08
16
+
17
+ ### Breaking
18
+
19
+ - Config option `fixture_path` was renamed to `static_db_path`.
20
+ - The Rails boot sequence hooks are no longer active automatically. You need to opt-in via the config options `load` and `dump`.
21
+ - The Rails boot sequence hooks no longer run for any `* build` command. They only run for `parklife build`.
22
+
23
+ ### Non-breaking
24
+
25
+ - All config options now support Procs or any other object responding to `.call()`.
26
+ - The default Proc for config option `static_db_path` now gets evaluated correctly.
27
+ - Internal code cleanup
28
+
29
+ ## [0.1.1] - 2026-05-03
30
+
31
+ ### Breaking
32
+
33
+ -
34
+
35
+ ### Non-breaking
36
+
37
+ - Remove unused dependency on `ostruct`
38
+
15
39
  ## [0.1.0] - 2026-05-03
16
40
 
17
41
  ### Breaking
data/README.md CHANGED
@@ -3,11 +3,19 @@
3
3
 
4
4
  # static_db
5
5
 
6
- Dump DB contents to YAML and load them back again. Aimed at SQLite. Committable to git.
6
+ Dump DB contents to YAML and load them back again.
7
7
 
8
- ## Installation
8
+ This gem provides:
9
+ - Methods: `StaticDb::Load.new.perform` and `StaticDb::Dump.new.perform`
10
+ - Rake tasks: `static:load` and `static:dump` (available automatically in Rails projects)
11
+ - Hooks for the Rails boot sequence: off by default, but the main purpose of this gem. See configuration below.
12
+
13
+ > ℹ️ The original main use case for this gem are static site generators built on top of Ruby on Rails.
14
+ > However, the DB (de)serialization functionality is useful enough on its own, so the decision was made
15
+ > to disable any behavior by default, which could result in data loss for regular Rails applications.
16
+ > You can opt into the Rails boot sequence hooks via config.
9
17
 
10
- > ⚠️ This gem modifies the Rails startup sequence. Don't use this gem unless you want to build a static site generator. This gem also creates and drops the DB for you.
18
+ ## Installation
11
19
 
12
20
  Add it to your Rails project:
13
21
 
@@ -16,26 +24,36 @@ Add it to your Rails project:
16
24
  gem "static_db"
17
25
  ```
18
26
 
27
+ This example initializer shows a flexible way how to opt into the Rails boot sequency hooks:
28
+
19
29
  ```ruby
20
30
  # config/initializer/static_db.rb
21
31
  StaticDb.configure do |config|
22
- # `content/data` is the default. You only need this initializer,
23
- # if you want a custom path.
24
- config.fixture_path = Rails.root.join("content", "data")
32
+ config.static_db_path = Rails.root.join("content", "data")
33
+
34
+ # Selectively activate loading and dumping. Active by default. Set to any other value to disable.
35
+ config.load = ENV["STATIC_DB"].in? [ "load", nil, "on", "true", "1" ]
36
+ config.dump = ENV["STATIC_DB"].in? [ "dump", nil, "on", "true", "1" ]
25
37
  end
26
38
  ```
27
39
 
28
- ## Usage
40
+ Now, starting your Rails server will reset your DB and load YAML fixtures from `content/data`. Exiting the server with `Ctrl+C` will dump out your DB as YAML fixtures to that directory.
29
41
 
30
- > ⚠️ Only use on Rails projects with SQLite. Have a valid `db/schema.rb`.
42
+ All config options support procs.
31
43
 
32
- Start your app with `bin/dev`. You will notice that a DB gets created for you. It will be empty.
44
+ ## Hook activation
33
45
 
34
- Create some records. Then, stop your server with Ctrl+C.
46
+ The boot sequence hooks are active in the following scenarios:
47
+ - When you run any server command: `bin/rails s`
48
+ - When you run any console command: `bin/rails c`
49
+ - When you run `parklife build`
35
50
 
36
- The DB contents will have been dumped to `content/data`.
51
+ > ℹ️ If you already have your dev server running and want to start an additional console, avoid conflicts by using `STATIC_DB=0 bin/rails c` (with the example initializer from above).
37
52
 
38
- Restart your server with `bin/dev`. Your SQLite DB will be dropped and recreated with all previously stored data from `content/data`.
53
+ The boot sequence hooks are inactive in all other cases, e.g.:
54
+ - When you run tests: `bin/rails t` or `bin/rails test:system`
55
+ - When you run migrations: `bin/rails db:migrate`
56
+ - When you run any other rake tasks
39
57
 
40
58
  ## Contributing
41
59
 
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ begin
7
7
  require "rubocop/rake_task"
8
8
  RuboCop::RakeTask.new
9
9
  rescue LoadError
10
- task(:rubocop) {}
10
+ task(:rubocop) { }
11
11
  end
12
12
 
13
13
  task default: %w[rubocop spec]
@@ -1,21 +1,18 @@
1
1
  module StaticDb
2
2
  class Dump
3
+ attr_reader :models_to_be_saved
3
4
 
4
- attr_reader :fixture_path, :models_to_be_saved
5
-
6
- def initialize(fixture_path: StaticDb.config.fixture_path)
7
- @fixture_path = Pathname.new(fixture_path)
5
+ def initialize(static_db_path: StaticDb.path)
6
+ @static_db_path = Pathname.new(static_db_path)
8
7
  @models_to_be_saved = models
9
8
  end
10
9
 
11
10
  def perform
12
- exit 1 if $skip_active_fixtures_dump
11
+ exit 1 if $skip_static_db_dump
13
12
 
14
13
  validate_records!
15
-
16
- puts green("Dumping fixtures ...")
17
- dump_fixtures!
18
- puts green("Done!")
14
+ reset_data_directory!
15
+ dump_data!
19
16
  end
20
17
 
21
18
  private
@@ -27,84 +24,76 @@ module StaticDb
27
24
 
28
25
  models_to_be_saved.each do |model|
29
26
  model.find_each do |record|
30
- unless record.valid?
31
- errors << { model: model.name, slug: record.slug, errors: record.errors.full_messages }
32
- end
27
+ next if record.valid?
28
+
29
+ debug_data = { model: model.name, id: record.id, errors: record.errors.full_messages }
30
+ debug_data[:slug] = record.slug if record.respond_to?(:slug)
31
+
32
+ errors << debug_data
33
33
  end
34
34
  end
35
35
 
36
36
  if errors.any?
37
37
  puts red("Found #{errors.length} invalid records!")
38
38
  errors.each do |error|
39
- puts "- #{error[:model]} #{error[:slug]}: #{error[:errors].join(", ")}"
39
+ puts "- #{error[:model]} #{error[:slug] || error[:id]}: #{error[:errors].join(", ")}"
40
40
  end
41
- if ARGV.first == "build"
41
+
42
+ if StaticDb.parklife?
42
43
  puts red("Build failed!")
43
44
  exit 1
44
45
  else
45
- puts red("Please fix the invalid records before creating a PR!")
46
+ puts red("PROCEEDING TO DUMP DATA DESPITE VALIDATION ERRORS!!!")
47
+ puts
48
+ puts red("Set `config.load = false` to preserve the invalid data in your DB when restarting. Then you can fix the validation errors and retry dumping.")
46
49
  end
47
50
  else
48
51
  puts green("Done!")
49
52
  end
50
53
  end
51
54
 
52
- def dump_fixtures!
53
- reset_data_directory!
54
- models_to_be_saved.each { |model| format_and_write_yaml_file!(model) }
55
- end
56
-
57
55
  def reset_data_directory!
58
- FileUtils.rm_rf(fixture_path)
59
- FileUtils.mkdir_p(fixture_path)
56
+ FileUtils.rm_rf(@static_db_path)
57
+ FileUtils.mkdir_p(@static_db_path)
60
58
  end
61
59
 
62
- def format_and_write_yaml_file!(model)
63
- instances = fetch_model_instances(model)
64
- output = format_instances(model: model, instances: instances)
65
- write_yaml_file!(model: model, data: output)
66
- end
60
+ def dump_data!
61
+ puts green("Dumping data ...")
67
62
 
68
- def fetch_model_instances(model)
69
- model.unscoped.all.order('id ASC')
70
- end
63
+ models_to_be_saved.each { |model| write_file!(path: file_path(model), data: data(model)) }
71
64
 
72
- # TODO: check against old implementation!
73
- def format_instances(model:, instances:)
74
- output = {}
65
+ puts green("Done!")
66
+ end
75
67
 
76
- instances.each do |instance|
77
- attrs = {}
68
+ def write_file!(path:, data:)
69
+ File.open(path, "w") { |file| file << data.to_yaml }
70
+ end
78
71
 
79
- model.columns.each do |column|
80
- value = instance.read_attribute_before_type_cast(column.name)
81
- attrs[column.name] = value unless value.nil?
82
- end
72
+ def file_path(model)
73
+ File.join(@static_db_path, "#{model.table_name}.yml")
74
+ end
83
75
 
84
- output["#{model}_#{instance.id}"] = attrs
76
+ def data(model)
77
+ model.unscoped.order(:id).to_h do |instance|
78
+ [ "#{model}_#{instance.id}", instance_data(instance, model.columns) ]
85
79
  end
86
-
87
- output
88
80
  end
89
81
 
90
- def write_yaml_file!(model:, data:)
91
- File.open(yaml_file_path(model), 'w') { |file| file << data.to_yaml }
82
+ def instance_data(instance, columns)
83
+ columns.filter_map do |column|
84
+ value = instance.read_attribute_before_type_cast(column.name)
85
+ next if value.nil?
86
+
87
+ [ column.name, value ]
88
+ end.to_h
92
89
  end
93
90
 
94
91
  def models
95
92
  Rails.application.eager_load!
96
- models = ActiveRecord::Base.descendants
97
- models.select! { |model| model.table_exists? && model.any? }
98
- models.delete(ActiveRecord::SchemaMigration)
99
- models
100
- end
101
-
102
- def yaml_file_path(model)
103
- File.join(fixture_path, generate_file_name(model) + '.yml')
104
- end
105
93
 
106
- def generate_file_name(model)
107
- model.table_name
94
+ ActiveRecord::Base.descendants.select do |model|
95
+ model.table_exists? && model.any? && model != ActiveRecord::SchemaMigration
96
+ end
108
97
  end
109
98
 
110
99
  def green(text)
@@ -114,6 +103,5 @@ module StaticDb
114
103
  def red(text)
115
104
  "\e[31m#{text}\e[0m"
116
105
  end
117
-
118
106
  end
119
107
  end
@@ -11,7 +11,21 @@ module StaticDb # :nodoc:
11
11
  # - regular initializers from `config/initializers/`
12
12
  include StaticDb::Configurable
13
13
 
14
- config_accessor :fixture_path, instance_accessor: false, default: -> { Rails.root.join("content", "data") }
14
+ config_accessor :static_db_path, instance_accessor: false, default: -> { Rails.root.join("content", "data") }
15
+ config_accessor :load, instance_accessor: false, default: false
16
+ config_accessor :dump, instance_accessor: false, default: false
17
+
18
+ def self.unproc(value_or_proc)
19
+ value_or_proc.respond_to?(:call) ? value_or_proc.call : value_or_proc
20
+ end
21
+
22
+ def self.path = unproc(config.static_db_path)
23
+ def self.load? = unproc(config.load)
24
+ def self.dump? = unproc(config.dump)
25
+
26
+ def self.parklife?
27
+ File.basename($PROGRAM_NAME) == "parklife" && ARGV.first == "build"
28
+ end
15
29
 
16
30
  class Engine < ::Rails::Engine # :nodoc:
17
31
  isolate_namespace StaticDb
@@ -21,16 +35,15 @@ module StaticDb # :nodoc:
21
35
  end
22
36
 
23
37
  initializer "static_db.configure" do |app|
24
- if defined?(Rails::Server) || defined?(Rails::Console) || ARGV.first == "build"
38
+ if defined?(Rails::Server) || defined?(Rails::Console) || StaticDb.parklife?
25
39
  Rails.application.config.after_initialize do
26
- StaticDb::Load.new.perform
40
+ StaticDb::Load.new.perform if StaticDb.load?
27
41
  end
28
42
 
29
43
  at_exit do
30
- StaticDb::Dump.new.perform
44
+ StaticDb::Dump.new.perform if StaticDb.dump?
31
45
  end
32
46
  end
33
47
  end
34
-
35
48
  end
36
49
  end
@@ -1,32 +1,38 @@
1
1
  module StaticDb
2
2
  class Load
3
-
4
- attr_reader :fixture_path
5
-
6
- def initialize(fixture_path: StaticDb.config.fixture_path)
7
- @fixture_path = Pathname.new(fixture_path)
3
+ def initialize(static_db_path: StaticDb.path)
4
+ @static_db_path = Pathname.new(static_db_path)
8
5
  end
9
6
 
10
7
  def perform
11
- puts green("Loading fixtures ...")
12
- system("bin/rails", "db:drop", "db:create", "db:schema:load")
13
- load_fixtures!
14
- puts green("Done!")
8
+ reset_database!
9
+ load_data!
15
10
  rescue => e
16
- puts red("Failed to load fixtures: #{e.message}")
17
- puts red("Exiting and skipping active_fixtures:dump!")
18
- $skip_active_fixtures_dump = true
11
+ puts red("Failed to load data: #{e.message}")
12
+ puts red("Exiting and skipping StaticDb::Dump.")
13
+ $skip_static_db_dump = true
19
14
  exit 1
20
15
  end
21
16
 
22
17
  private
23
18
 
24
- def load_fixtures!
25
- base_names = Dir.glob(File.join(fixture_path, "*.yml")).map do |file|
19
+ def reset_database!
20
+ puts green("Resetting database ...")
21
+
22
+ system("bin/rails", "db:drop", "db:create", "db:schema:load")
23
+
24
+ puts green("Done!")
25
+ end
26
+
27
+ def load_data!
28
+ puts green("Loading data ...")
29
+
30
+ base_names = Dir.glob(File.join(@static_db_path, "*.yml")).map do |file|
26
31
  File.basename(file, ".*")
27
32
  end
33
+ ActiveRecord::FixtureSet.create_fixtures(@static_db_path, base_names)
28
34
 
29
- ActiveRecord::FixtureSet.create_fixtures(fixture_path, base_names)
35
+ puts green("Done!")
30
36
  end
31
37
 
32
38
  def green(text)
@@ -36,6 +42,5 @@ module StaticDb
36
42
  def red(text)
37
43
  "\e[31m#{text}\e[0m"
38
44
  end
39
-
40
45
  end
41
46
  end
@@ -1,19 +1,19 @@
1
1
  namespace :static do
2
- desc "Create fixtures from database; accepts optional path argument"
3
- task :dump, [:path] => :environment do |t, args|
4
- if args[:path].blank?
5
- StaticDb::Dump.new.perform
2
+ desc "Reset database and load YAML fixtures"
3
+ task :load, [ :static_db_path ] => :environment do |t, args|
4
+ if args[:static_db_path].blank?
5
+ StaticDb::Load.new.perform
6
6
  else
7
- StaticDb::Dump.new(fixture_path: Rails.root.join(args[:path])).perform
7
+ StaticDb::Load.new(static_db_path: Rails.root.join(args[:static_db_path])).perform
8
8
  end
9
9
  end
10
10
 
11
- desc "Create database from fixtures; accepts optional path argument"
12
- task :load, [:path] => :environment do |t, args|
13
- if args[:path].blank?
14
- StaticDb::Load.new.perform
11
+ desc "Dump database to YAML fixtures"
12
+ task :dump, [ :static_db_path ] => :environment do |t, args|
13
+ if args[:static_db_path].blank?
14
+ StaticDb::Dump.new.perform
15
15
  else
16
- StaticDb::Load.new(fixture_path: Rails.root.join(args[:path])).perform
16
+ StaticDb::Dump.new(static_db_path: Rails.root.join(args[:static_db_path])).perform
17
17
  end
18
18
  end
19
19
  end
@@ -1,3 +1,3 @@
1
1
  module StaticDb # :nodoc:
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: static_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Klaus Weidinger
@@ -23,20 +23,6 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '7.2'
26
- - !ruby/object:Gem::Dependency
27
- name: ostruct
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '0.6'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '0.6'
40
26
  description: Dump DB contents to YAML and load them back again. Aimed at SQLite. Committable
41
27
  to git.
42
28
  email: