fx 0.8.0 → 0.10.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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -7
  3. data/CHANGELOG.md +150 -0
  4. data/CONTRIBUTING.md +3 -3
  5. data/Gemfile +11 -1
  6. data/README.md +2 -0
  7. data/bin/rake +2 -3
  8. data/bin/rspec +13 -3
  9. data/bin/standardrb +27 -0
  10. data/bin/yard +13 -3
  11. data/fx.gemspec +10 -15
  12. data/lib/fx/adapters/postgres/connection.rb +20 -0
  13. data/lib/fx/adapters/postgres/functions.rb +11 -28
  14. data/lib/fx/adapters/postgres/query_executor.rb +34 -0
  15. data/lib/fx/adapters/postgres/triggers.rb +14 -29
  16. data/lib/fx/adapters/postgres.rb +16 -24
  17. data/lib/fx/command_recorder.rb +87 -6
  18. data/lib/fx/configuration.rb +2 -27
  19. data/lib/fx/definition.rb +16 -6
  20. data/lib/fx/function.rb +3 -3
  21. data/lib/fx/schema_dumper.rb +37 -5
  22. data/lib/fx/statements.rb +231 -6
  23. data/lib/fx/trigger.rb +3 -3
  24. data/lib/fx/version.rb +1 -1
  25. data/lib/fx.rb +30 -12
  26. data/lib/generators/fx/function/function_generator.rb +50 -53
  27. data/lib/generators/fx/function/templates/db/migrate/create_function.erb +1 -1
  28. data/lib/generators/fx/function/templates/db/migrate/update_function.erb +1 -1
  29. data/lib/generators/fx/migration_helper.rb +53 -0
  30. data/lib/generators/fx/name_helper.rb +33 -0
  31. data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +1 -1
  32. data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +1 -1
  33. data/lib/generators/fx/trigger/trigger_generator.rb +44 -67
  34. data/lib/generators/fx/version_helper.rb +55 -0
  35. data/spec/acceptance/user_manages_functions_spec.rb +7 -7
  36. data/spec/acceptance/user_manages_triggers_spec.rb +11 -11
  37. data/spec/acceptance_helper.rb +4 -4
  38. data/spec/dummy/config/application.rb +5 -1
  39. data/spec/features/functions/migrations_spec.rb +5 -5
  40. data/spec/features/functions/revert_spec.rb +5 -5
  41. data/spec/features/triggers/migrations_spec.rb +7 -7
  42. data/spec/features/triggers/revert_spec.rb +9 -9
  43. data/spec/fx/adapters/postgres/functions_spec.rb +33 -30
  44. data/spec/fx/adapters/postgres/query_executor_spec.rb +75 -0
  45. data/spec/fx/adapters/postgres/triggers_spec.rb +41 -38
  46. data/spec/fx/adapters/postgres_spec.rb +155 -115
  47. data/spec/fx/command_recorder_spec.rb +27 -25
  48. data/spec/fx/configuration_spec.rb +20 -9
  49. data/spec/fx/definition_spec.rb +31 -39
  50. data/spec/fx/function_spec.rb +45 -48
  51. data/spec/fx/schema_dumper_spec.rb +169 -0
  52. data/spec/fx/statements_spec.rb +217 -0
  53. data/spec/fx/trigger_spec.rb +37 -40
  54. data/spec/fx_spec.rb +28 -0
  55. data/spec/generators/fx/function/function_generator_spec.rb +11 -11
  56. data/spec/generators/fx/migration_helper_spec.rb +133 -0
  57. data/spec/generators/fx/name_helper_spec.rb +114 -0
  58. data/spec/generators/fx/trigger/trigger_generator_spec.rb +45 -22
  59. data/spec/generators/fx/version_helper_spec.rb +157 -0
  60. data/spec/spec_helper.rb +7 -0
  61. data/spec/support/definition_helpers.rb +2 -6
  62. data/spec/support/generator_setup.rb +46 -5
  63. data/spec/support/warning_helper.rb +5 -0
  64. metadata +40 -165
  65. data/lib/fx/command_recorder/arguments.rb +0 -43
  66. data/lib/fx/command_recorder/function.rb +0 -30
  67. data/lib/fx/command_recorder/trigger.rb +0 -30
  68. data/lib/fx/schema_dumper/function.rb +0 -38
  69. data/lib/fx/schema_dumper/trigger.rb +0 -29
  70. data/lib/fx/statements/function.rb +0 -113
  71. data/lib/fx/statements/trigger.rb +0 -144
  72. data/spec/fx/command_recorder/arguments_spec.rb +0 -41
  73. data/spec/fx/schema_dumper/function_spec.rb +0 -78
  74. data/spec/fx/schema_dumper/trigger_spec.rb +0 -40
  75. data/spec/fx/statements/function_spec.rb +0 -103
  76. data/spec/fx/statements/trigger_spec.rb +0 -132
@@ -0,0 +1,133 @@
1
+ require "spec_helper"
2
+ require "generators/fx/migration_helper"
3
+
4
+ RSpec.describe Fx::Generators::MigrationHelper do
5
+ describe "#skip_creation?" do
6
+ it "returns false by default" do
7
+ helper = described_class.new({})
8
+
9
+ expect(helper.skip_creation?).to be(false)
10
+ end
11
+
12
+ it "returns true when migration option is false" do
13
+ helper = described_class.new(migration: false)
14
+
15
+ expect(helper.skip_creation?).to be(true)
16
+ end
17
+ end
18
+
19
+ describe "#active_record_migration_class" do
20
+ it "returns versioned migration class when current_version is available" do
21
+ allow(ActiveRecord::Migration).to receive(:current_version)
22
+ .and_return(7.0)
23
+
24
+ helper = described_class.new({})
25
+
26
+ expect(helper.active_record_migration_class).to eq(
27
+ "ActiveRecord::Migration[7.0]"
28
+ )
29
+ end
30
+
31
+ it "returns base migration class when current_version is not available" do
32
+ allow(ActiveRecord::Migration).to receive(:respond_to?)
33
+ .with(:current_version)
34
+ .and_return(false)
35
+
36
+ helper = described_class.new({})
37
+
38
+ expect(helper.active_record_migration_class).to eq(
39
+ "ActiveRecord::Migration"
40
+ )
41
+ end
42
+ end
43
+
44
+ describe "#update_migration_class_name" do
45
+ it "generates correct class name for functions" do
46
+ helper = described_class.new({})
47
+
48
+ result = helper.update_migration_class_name(
49
+ object_type: :function,
50
+ class_name: "TestFunction",
51
+ version: 3
52
+ )
53
+
54
+ expect(result).to eq("UpdateFunctionTestFunctionToVersion3")
55
+ end
56
+
57
+ it "generates correct class name for triggers" do
58
+ helper = described_class.new({})
59
+
60
+ result = helper.update_migration_class_name(
61
+ object_type: :trigger,
62
+ class_name: "TestTrigger",
63
+ version: 2
64
+ )
65
+
66
+ expect(result).to eq("UpdateTriggerTestTriggerToVersion2")
67
+ end
68
+ end
69
+
70
+ describe "#migration_template_info" do
71
+ it "returns create template info for new objects" do
72
+ helper = described_class.new({})
73
+
74
+ result = helper.migration_template_info(
75
+ object_type: :function,
76
+ file_name: "test_func",
77
+ updating_existing: false,
78
+ version: 1
79
+ )
80
+
81
+ expect(result).to eq({
82
+ template: "db/migrate/create_function.erb",
83
+ filename: "db/migrate/create_function_test_func.rb"
84
+ })
85
+ end
86
+
87
+ it "returns update template info for existing objects" do
88
+ helper = described_class.new({})
89
+
90
+ result = helper.migration_template_info(
91
+ object_type: :trigger,
92
+ file_name: "test_trigger",
93
+ updating_existing: true,
94
+ version: 3
95
+ )
96
+
97
+ expect(result).to eq({
98
+ template: "db/migrate/update_trigger.erb",
99
+ filename: "db/migrate/update_trigger_test_trigger_to_version_3.rb"
100
+ })
101
+ end
102
+
103
+ it "handles different object types correctly" do
104
+ helper = described_class.new({})
105
+
106
+ function_result = helper.migration_template_info(
107
+ object_type: :function,
108
+ file_name: "my_function",
109
+ updating_existing: true,
110
+ version: 2
111
+ )
112
+ trigger_result = helper.migration_template_info(
113
+ object_type: :trigger,
114
+ file_name: "my_trigger",
115
+ updating_existing: true,
116
+ version: 2
117
+ )
118
+
119
+ expect(function_result.fetch(:template)).to eq(
120
+ "db/migrate/update_function.erb"
121
+ )
122
+ expect(trigger_result.fetch(:template)).to eq(
123
+ "db/migrate/update_trigger.erb"
124
+ )
125
+ expect(function_result.fetch(:filename)).to eq(
126
+ "db/migrate/update_function_my_function_to_version_2.rb"
127
+ )
128
+ expect(trigger_result.fetch(:filename)).to eq(
129
+ "db/migrate/update_trigger_my_trigger_to_version_2.rb"
130
+ )
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,114 @@
1
+ require "spec_helper"
2
+ require "generators/fx/name_helper"
3
+
4
+ RSpec.describe Fx::Generators::NameHelper do
5
+ describe ".format_for_migration" do
6
+ it "returns symbol format for simple names" do
7
+ result = described_class.format_for_migration("simple_name")
8
+
9
+ expect(result).to eq(":simple_name")
10
+ end
11
+
12
+ it "returns quoted string format for schema-qualified names" do
13
+ result = described_class.format_for_migration("schema.function_name")
14
+
15
+ expect(result).to eq("\"schema.function_name\"")
16
+ end
17
+
18
+ it "handles names with multiple dots" do
19
+ result = described_class.format_for_migration("db.schema.function")
20
+
21
+ expect(result).to eq("\"db.schema.function\"")
22
+ end
23
+
24
+ it "handles empty names" do
25
+ result = described_class.format_for_migration("")
26
+
27
+ expect(result).to eq(":")
28
+ end
29
+ end
30
+
31
+ describe ".format_table_name_from_hash" do
32
+ it "formats table_name key correctly" do
33
+ table_hash = {"table_name" => "users"}
34
+
35
+ result = described_class.format_table_name_from_hash(table_hash)
36
+
37
+ expect(result).to eq(":users")
38
+ end
39
+
40
+ it "formats on key correctly" do
41
+ table_hash = {"on" => "posts"}
42
+
43
+ result = described_class.format_table_name_from_hash(table_hash)
44
+
45
+ expect(result).to eq(":posts")
46
+ end
47
+
48
+ it "prefers table_name over on when both are present" do
49
+ table_hash = {"table_name" => "users", "on" => "posts"}
50
+
51
+ result = described_class.format_table_name_from_hash(table_hash)
52
+
53
+ expect(result).to eq(":users")
54
+ end
55
+
56
+ it "handles schema-qualified table names" do
57
+ table_hash = {"table_name" => "public.users"}
58
+
59
+ result = described_class.format_table_name_from_hash(table_hash)
60
+
61
+ expect(result).to eq("\"public.users\"")
62
+ end
63
+
64
+ it "raises error when neither key is present" do
65
+ table_hash = {"something_else" => "value"}
66
+
67
+ expect {
68
+ described_class.format_table_name_from_hash(table_hash)
69
+ }.to raise_error(
70
+ ArgumentError,
71
+ "Either `table_name:NAME` or `on:NAME` must be specified"
72
+ )
73
+ end
74
+
75
+ it "raises error when both keys have nil values" do
76
+ table_hash = {"table_name" => nil, "on" => nil}
77
+
78
+ expect {
79
+ described_class.format_table_name_from_hash(table_hash)
80
+ }.to raise_error(
81
+ ArgumentError,
82
+ "Either `table_name:NAME` or `on:NAME` must be specified"
83
+ )
84
+ end
85
+
86
+ it "uses on key when table_name is nil" do
87
+ table_hash = {"table_name" => nil, "on" => "comments"}
88
+
89
+ result = described_class.format_table_name_from_hash(table_hash)
90
+
91
+ expect(result).to eq(":comments")
92
+ end
93
+ end
94
+
95
+ describe ".validate_and_format" do
96
+ it "formats valid names correctly" do
97
+ result = described_class.validate_and_format("test_function")
98
+
99
+ expect(result).to eq(":test_function")
100
+ end
101
+
102
+ it "formats schema-qualified names correctly" do
103
+ result = described_class.validate_and_format("schema.test")
104
+
105
+ expect(result).to eq("\"schema.test\"")
106
+ end
107
+
108
+ it "raises error for blank names" do
109
+ expect {
110
+ described_class.validate_and_format("")
111
+ }.to raise_error(ArgumentError, "Name cannot be blank")
112
+ end
113
+ end
114
+ end
@@ -1,17 +1,20 @@
1
1
  require "spec_helper"
2
2
  require "generators/fx/trigger/trigger_generator"
3
3
 
4
- describe Fx::Generators::TriggerGenerator, :generator do
4
+ RSpec.describe Fx::Generators::TriggerGenerator, :generator do
5
5
  it "creates a trigger definition file, and a migration" do
6
6
  migration = file("db/migrate/create_trigger_test.rb")
7
7
  trigger_definition = file("db/triggers/test_v01.sql")
8
8
 
9
- run_generator ["test", "table_name" => "some_table"]
9
+ run_generator(
10
+ described_class,
11
+ ["test", {"table_name" => "some_table"}]
12
+ )
10
13
 
11
14
  expect(trigger_definition).to exist
12
- expect(migration).to be_a_migration
13
- expect(migration_file(migration)).to contain "CreateTriggerTest"
14
- expect(migration_file(migration)).to contain "on: :some_table"
15
+ expect_to_be_a_migration(migration)
16
+ expect(migration_content(migration)).to include("CreateTriggerTest")
17
+ expect(migration_content(migration)).to include("on: :some_table")
15
18
  end
16
19
 
17
20
  context "when passed --no-migration" do
@@ -19,10 +22,14 @@ describe Fx::Generators::TriggerGenerator, :generator do
19
22
  migration = file("db/migrate/create_trigger_test.rb")
20
23
  trigger_definition = file("db/triggers/test_v01.sql")
21
24
 
22
- run_generator ["test", {"table_name" => "some_table"}, "--no-migration"]
25
+ run_generator(
26
+ described_class,
27
+ ["test", {"table_name" => "some_table"}],
28
+ {migration: false}
29
+ )
23
30
 
24
31
  expect(trigger_definition).to exist
25
- expect(migration_file(migration)).not_to exist
32
+ expect(migration).not_to exist
26
33
  end
27
34
  end
28
35
 
@@ -30,30 +37,46 @@ describe Fx::Generators::TriggerGenerator, :generator do
30
37
  migration = file("db/migrate/create_trigger_test.rb")
31
38
  trigger_definition = file("db/triggers/test_v01.sql")
32
39
 
33
- run_generator ["test", "on" => "some_table"]
40
+ run_generator(
41
+ described_class,
42
+ ["test", {"on" => "some_table"}]
43
+ )
34
44
 
35
45
  expect(trigger_definition).to exist
36
- expect(migration).to be_a_migration
37
- expect(migration_file(migration)).to contain "CreateTriggerTest"
38
- expect(migration_file(migration)).to contain "on: :some_table"
46
+ expect_to_be_a_migration(migration)
47
+ expect(migration_content(migration)).to include("CreateTriggerTest")
48
+ expect(migration_content(migration)).to include("on: :some_table")
39
49
  end
40
50
 
41
51
  it "requires `table_name` or `on` to be specified" do
42
- expect {
43
- run_generator ["test", "foo" => "some_table"]
44
- }.to raise_error ArgumentError
52
+ expect do
53
+ run_generator(
54
+ described_class,
55
+ ["test", {"foo" => "some_table"}]
56
+ )
57
+ end.to raise_error(ArgumentError)
45
58
  end
46
59
 
47
60
  it "updates an existing trigger" do
48
- allow(Dir).to receive(:entries).and_return(["test_v01.sql"])
49
- migration = file("db/migrate/update_trigger_test_to_version_2.rb")
50
- trigger_definition = file("db/triggers/test_v02.sql")
61
+ with_trigger_definition(
62
+ name: "test",
63
+ version: 1,
64
+ sql_definition: "hello"
65
+ ) do
66
+ migration = file("db/migrate/update_trigger_test_to_version_2.rb")
67
+ trigger_definition = file("db/triggers/test_v02.sql")
51
68
 
52
- run_generator ["test", "table_name" => "some_table"]
69
+ run_generator(
70
+ described_class,
71
+ ["test", {"table_name" => "some_table"}]
72
+ )
53
73
 
54
- expect(trigger_definition).to exist
55
- expect(migration).to be_a_migration
56
- expect(migration_file(migration)).to contain "UpdateTriggerTestToVersion2"
57
- expect(migration_file(migration)).to contain "on: :some_table"
74
+ expect(trigger_definition).to exist
75
+ expect_to_be_a_migration(migration)
76
+ expect(migration_content(migration)).to include(
77
+ "UpdateTriggerTestToVersion2"
78
+ )
79
+ expect(migration_content(migration)).to include("on: :some_table")
80
+ end
58
81
  end
59
82
  end
@@ -0,0 +1,157 @@
1
+ require "spec_helper"
2
+ require "generators/fx/version_helper"
3
+
4
+ RSpec.describe Fx::Generators::VersionHelper do
5
+ describe "#previous_version" do
6
+ it "returns 0 when no existing versions found" do
7
+ with_temp_directory do |temp_dir|
8
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
9
+
10
+ expect(helper.previous_version).to eq(0)
11
+ end
12
+ end
13
+
14
+ it "returns highest version number from existing files" do
15
+ with_temp_directory do |temp_dir|
16
+ create_version_file(temp_dir, "test_function", 1)
17
+ create_version_file(temp_dir, "test_function", 3)
18
+ create_version_file(temp_dir, "test_function", 2)
19
+
20
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
21
+
22
+ expect(helper.previous_version).to eq(3)
23
+ end
24
+ end
25
+
26
+ it "ignores files that don't match the pattern" do
27
+ with_temp_directory do |temp_dir|
28
+ create_version_file(temp_dir, "test_function", 2)
29
+ FileUtils.touch(temp_dir.join("other_function_v3.sql"))
30
+ FileUtils.touch(temp_dir.join("test_function.sql"))
31
+
32
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
33
+
34
+ expect(helper.previous_version).to eq(2)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "#current_version" do
40
+ it "returns previous version + 1" do
41
+ with_temp_directory do |temp_dir|
42
+ create_version_file(temp_dir, "test_function", 5)
43
+
44
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
45
+
46
+ expect(helper.current_version).to eq(6)
47
+ end
48
+ end
49
+
50
+ it "returns 1 when no previous versions exist" do
51
+ with_temp_directory do |temp_dir|
52
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
53
+
54
+ expect(helper.current_version).to eq(1)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#updating_existing?" do
60
+ it "returns false when no previous versions exist" do
61
+ with_temp_directory do |temp_dir|
62
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
63
+
64
+ expect(helper.updating_existing?).to be false
65
+ end
66
+ end
67
+
68
+ it "returns true when previous versions exist" do
69
+ with_temp_directory do |temp_dir|
70
+ create_version_file(temp_dir, "test_function", 1)
71
+
72
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
73
+
74
+ expect(helper.updating_existing?).to be true
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "#creating_new?" do
80
+ it "returns true when no previous versions exist" do
81
+ with_temp_directory do |temp_dir|
82
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
83
+
84
+ expect(helper.creating_new?).to be true
85
+ end
86
+ end
87
+
88
+ it "returns false when previous versions exist" do
89
+ with_temp_directory do |temp_dir|
90
+ create_version_file(temp_dir, "test_function", 1)
91
+
92
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
93
+
94
+ expect(helper.creating_new?).to be false
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#definition_for_version" do
100
+ it "returns function definition for function type" do
101
+ with_temp_directory do |temp_dir|
102
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
103
+ allow(Fx::Definition).to receive(:function)
104
+ .and_return("function_definition")
105
+
106
+ result = helper.definition_for_version(version: 2, type: :function)
107
+
108
+ expect(result).to eq("function_definition")
109
+ expect(Fx::Definition).to have_received(:function).with(
110
+ name: "test_function",
111
+ version: 2
112
+ )
113
+ end
114
+ end
115
+
116
+ it "returns trigger definition for trigger type" do
117
+ with_temp_directory do |temp_dir|
118
+ helper = described_class.new(file_name: "test_trigger", definition_path: temp_dir)
119
+ allow(Fx::Definition).to receive(:trigger)
120
+ .and_return("trigger_definition")
121
+
122
+ result = helper.definition_for_version(version: 3, type: :trigger)
123
+
124
+ expect(result).to eq("trigger_definition")
125
+ expect(Fx::Definition).to have_received(:trigger).with(
126
+ name: "test_trigger",
127
+ version: 3
128
+ )
129
+ end
130
+ end
131
+
132
+ it "raises error for unknown type" do
133
+ with_temp_directory do |temp_dir|
134
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
135
+
136
+ expect {
137
+ helper.definition_for_version(version: 1, type: :unknown)
138
+ }.to raise_error(
139
+ ArgumentError,
140
+ "Unknown type: unknown. Must be :function or :trigger"
141
+ )
142
+ end
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ def with_temp_directory
149
+ Dir.mktmpdir do |path|
150
+ yield Pathname.new(path)
151
+ end
152
+ end
153
+
154
+ def create_version_file(dir, name, version)
155
+ FileUtils.touch(dir.join("#{name}_v#{version}.sql"))
156
+ end
157
+ end
data/spec/spec_helper.rb CHANGED
@@ -4,11 +4,18 @@ require "database_cleaner"
4
4
  require File.expand_path("../dummy/config/environment", __FILE__)
5
5
  Dir["spec/support/**/*.rb"].sort.each { |file| load file }
6
6
 
7
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
8
+ require "fx"
9
+
7
10
  RSpec.configure do |config|
8
11
  config.order = "random"
12
+ config.disable_monkey_patching!
13
+
9
14
  DatabaseCleaner.strategy = :transaction
10
15
 
11
16
  config.around(:each, db: true) do |example|
17
+ ActiveRecord::Base.connection.execute("SET search_path TO DEFAULT;")
18
+
12
19
  DatabaseCleaner.start
13
20
  example.run
14
21
  DatabaseCleaner.clean
@@ -1,6 +1,6 @@
1
1
  module DefinitionHelpers
2
2
  def with_function_definition(name:, sql_definition:, version: 1, &block)
3
- definition = Fx::Definition.new(name: name, version: version)
3
+ definition = Fx::Definition.function(name: name, version: version)
4
4
 
5
5
  with_definition(
6
6
  definition: definition,
@@ -10,11 +10,7 @@ module DefinitionHelpers
10
10
  end
11
11
 
12
12
  def with_trigger_definition(name:, sql_definition:, version: 1, &block)
13
- definition = Fx::Definition.new(
14
- name: name,
15
- version: version,
16
- type: "trigger"
17
- )
13
+ definition = Fx::Definition.trigger(name: name, version: version)
18
14
 
19
15
  with_definition(
20
16
  definition: definition,
@@ -1,11 +1,52 @@
1
- require "ammeter/init"
1
+ module GeneratorSetup
2
+ RAILS_ROOT = Pathname.new(File.expand_path("../../../tmp/dummy", __dir__)).freeze
3
+ MIGRATION_TIMESTAMP_PATTERN = /\A\d{14}_/
4
+
5
+ def run_generator(generator_class, args = [], options = {})
6
+ allow(Rails).to receive(:root).and_return(RAILS_ROOT)
7
+ generator = generator_class.new(args, options, destination_root: RAILS_ROOT)
8
+
9
+ silence_stream($stdout) do
10
+ generator.invoke_all
11
+ end
12
+ end
13
+
14
+ def file(relative_path)
15
+ RAILS_ROOT.join(relative_path)
16
+ end
17
+
18
+ def migration_content(file_path)
19
+ migration_path = find_migration_files(file_path).first
20
+ return if migration_path.nil?
21
+
22
+ Pathname.new(migration_path).read
23
+ end
24
+
25
+ def find_migration_files(file_path)
26
+ directory = File.dirname(file_path)
27
+ basename = File.basename(file_path, ".rb")
28
+ Dir.glob(File.join(directory, "*#{basename}.rb"))
29
+ end
30
+
31
+ def expect_to_be_a_migration(pathname)
32
+ migration_files = find_migration_files(pathname)
33
+
34
+ expect(migration_files).to be_present,
35
+ "expected #{pathname} to be a migration file"
36
+ first_migration = migration_files.first
37
+ migration_basename = File.basename(first_migration)
38
+ expect(migration_basename).to match(MIGRATION_TIMESTAMP_PATTERN),
39
+ "expected #{migration_basename} to have timestamp prefix (format: YYYYMMDDHHMMSS_)"
40
+ end
41
+ end
2
42
 
3
43
  RSpec.configure do |config|
44
+ config.include GeneratorSetup, :generator
45
+
4
46
  config.before(:each, :generator) do
5
- fake_rails_root = File.expand_path("../../../tmp/dummy", __FILE__)
6
- allow(Rails).to receive(:root).and_return(Pathname.new(fake_rails_root))
47
+ FileUtils.rm_rf(GeneratorSetup::RAILS_ROOT) if File.exist?(GeneratorSetup::RAILS_ROOT)
48
+ FileUtils.mkdir_p(GeneratorSetup::RAILS_ROOT)
7
49
 
8
- destination fake_rails_root
9
- prepare_destination
50
+ allow(Rails).to receive(:root).and_return(Pathname.new(GeneratorSetup::RAILS_ROOT))
10
51
  end
11
52
  end
@@ -0,0 +1,5 @@
1
+ require "warning"
2
+
3
+ Warning.process do |_|
4
+ :raise
5
+ end