Skip to content

Commit 68d7723

Browse files
committed
Replace method_missing with define_singleton_method and rename classes
Use define_singleton_method in initialize instead of method_missing or anonymous subclasses. Extract metaprogramming into named private methods (define_table_method, define_column_methods, etc). Rename classes to use database/schema terminology: - GeneratorProxy -> Default - GeneratorContext -> DefaultContext - RowDSL -> RowDefinition - RecordBuilder -> RowBuilder - StableId -> Key - @generators -> @defaults - table_def -> table
1 parent f2afc4b commit 68d7723

12 files changed

Lines changed: 148 additions & 157 deletions

lib/fixturebot.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
require_relative "fixturebot/version"
44
require_relative "fixturebot/schema"
5-
require_relative "fixturebot/stable_id"
5+
require_relative "fixturebot/key"
66
require_relative "fixturebot/row"
7-
require_relative "fixturebot/generator_context"
8-
require_relative "fixturebot/generator_proxy"
9-
require_relative "fixturebot/row_dsl"
7+
require_relative "fixturebot/default_context"
8+
require_relative "fixturebot/default"
9+
require_relative "fixturebot/row_definition"
1010
require_relative "fixturebot/definition"
11-
require_relative "fixturebot/record_builder"
11+
require_relative "fixturebot/row_builder"
1212
require_relative "fixturebot/fixture_set"
1313
require_relative "fixturebot/yaml_dumper"
1414
require_relative "fixturebot/cli"

lib/fixturebot/default.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
module FixtureBot
4+
class Default
5+
def initialize(table, defaults)
6+
@defaults = defaults
7+
define_column_methods(table)
8+
end
9+
10+
private
11+
12+
def define_column_methods(table)
13+
table.columns.each do |col|
14+
define_singleton_method(col) do |&block|
15+
raise ArgumentError, "#{col} requires a block" unless block
16+
@defaults[col] = block
17+
end
18+
end
19+
end
20+
end
21+
end

lib/fixturebot/default_context.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module FixtureBot
4+
class DefaultContext
5+
def initialize(record_name:, literal_values: {})
6+
define_name_method(record_name, literal_values)
7+
define_literal_value_methods(literal_values)
8+
end
9+
10+
private
11+
12+
def define_name_method(record_name, literal_values)
13+
define_singleton_method(:name) do
14+
literal_values.key?(:name) ? literal_values[:name] : record_name
15+
end
16+
end
17+
18+
def define_literal_value_methods(literal_values)
19+
literal_values.each do |col, val|
20+
next if col == :name
21+
define_singleton_method(col) { val }
22+
end
23+
end
24+
end
25+
end

lib/fixturebot/definition.rb

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,43 @@
22

33
module FixtureBot
44
class Definition
5-
attr_reader :generators, :rows
5+
attr_reader :defaults, :rows
66

77
def initialize(schema)
88
@schema = schema
9-
@generators = {}
9+
@defaults = {}
1010
@rows = []
11-
@singular_to_table = {}
1211

13-
schema.tables.each_value do |table_def|
14-
@generators[table_def.name] = {}
15-
@singular_to_table[table_def.singular_name] = table_def
12+
schema.tables.each_value do |table|
13+
@defaults[table.name] = {}
14+
define_table_method(table)
1615
end
1716
end
1817

1918
private
2019

21-
def method_missing(method_name, *args, &block)
22-
table_def = @singular_to_table[method_name]
23-
return super unless table_def
24-
25-
record_name = args.first
26-
27-
if record_name.nil? && block.nil?
28-
GeneratorProxy.new(table_def, @generators[table_def.name])
29-
elsif record_name
30-
row_dsl = RowDSL.new(table_def, @schema)
31-
row_dsl.instance_eval(&block) if block
32-
@rows << Row.new(
33-
table: table_def.name,
34-
name: record_name,
35-
literal_values: row_dsl.literal_values,
36-
association_refs: row_dsl.association_refs,
37-
tag_refs: row_dsl.tag_refs
38-
)
39-
else
40-
raise ArgumentError, "#{table_def.singular_name} requires a record name or no arguments"
20+
def define_table_method(table)
21+
define_singleton_method(table.singular_name) do |record_name = nil, &block|
22+
if record_name.nil? && block.nil?
23+
Default.new(table, @defaults[table.name])
24+
elsif record_name
25+
add_row(table, record_name, block)
26+
else
27+
raise ArgumentError, "#{table.singular_name} requires a record name or no arguments"
28+
end
4129
end
4230
end
4331

44-
def respond_to_missing?(method_name, include_private = false)
45-
@singular_to_table.key?(method_name) || super
32+
def add_row(table, record_name, block)
33+
row_dsl = RowDefinition.new(table, @schema)
34+
row_dsl.instance_eval(&block) if block
35+
@rows << Row.new(
36+
table: table.name,
37+
name: record_name,
38+
literal_values: row_dsl.literal_values,
39+
association_refs: row_dsl.association_refs,
40+
tag_refs: row_dsl.tag_refs
41+
)
4642
end
4743
end
4844
end

lib/fixturebot/fixture_set.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ def initialize(schema, definition)
1111
schema.join_tables.each_key { |name| @tables[name] = {} }
1212

1313
definition.rows.each do |row|
14-
builder = RecordBuilder.new(
14+
builder = RowBuilder.new(
1515
row: row,
16-
table_def: schema.tables[row.table],
17-
generators: definition.generators[row.table],
16+
table: schema.tables[row.table],
17+
defaults: definition.defaults[row.table],
1818
join_tables: schema.join_tables
1919
)
2020

lib/fixturebot/generator_context.rb

Lines changed: 0 additions & 28 deletions
This file was deleted.

lib/fixturebot/generator_proxy.rb

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require "zlib"
44

55
module FixtureBot
6-
module StableId
6+
module Key
77
def self.generate(table_name, record_name)
88
Zlib.crc32("#{table_name}:#{record_name}") & 0x7FFFFFFF
99
end
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
# frozen_string_literal: true
22

33
module FixtureBot
4-
class RecordBuilder
5-
def initialize(row:, table_def:, generators:, join_tables:)
4+
class RowBuilder
5+
def initialize(row:, table:, defaults:, join_tables:)
66
@row = row
7-
@table_def = table_def
8-
@generators = generators
7+
@table = table
8+
@defaults = defaults
99
@join_tables = join_tables
1010
end
1111

1212
def id
13-
@id ||= StableId.generate(@row.table, @row.name)
13+
@id ||= Key.generate(@row.table, @row.name)
1414
end
1515

1616
def record
1717
result = { id: id }
18-
@table_def.columns.each do |col|
18+
@table.columns.each do |col|
1919
if @row.literal_values.key?(col)
2020
result[col] = @row.literal_values[col]
2121
elsif foreign_key_values.key?(col)
2222
result[col] = foreign_key_values[col]
23-
elsif generated_values.key?(col)
24-
result[col] = generated_values[col]
23+
elsif defaulted_values.key?(col)
24+
result[col] = defaulted_values[col]
2525
end
2626
end
2727
result
@@ -39,7 +39,7 @@ def join_rows
3939
private
4040

4141
def build_join_row(jt, other_table, tag_ref)
42-
other_id = StableId.generate(other_table, tag_ref)
42+
other_id = Key.generate(other_table, tag_ref)
4343

4444
if jt.left_table == @row.table
4545
{
@@ -58,17 +58,17 @@ def build_join_row(jt, other_table, tag_ref)
5858

5959
def foreign_key_values
6060
@foreign_key_values ||= @row.association_refs.each_with_object({}) do |(assoc_name, ref), hash|
61-
assoc = @table_def.belongs_to_associations.find { |a| a.name == assoc_name }
62-
hash[assoc.foreign_key] = StableId.generate(assoc.table, ref)
61+
assoc = @table.belongs_to_associations.find { |a| a.name == assoc_name }
62+
hash[assoc.foreign_key] = Key.generate(assoc.table, ref)
6363
end
6464
end
6565

66-
def generated_values
67-
@generated_values ||= @generators.each_with_object({}) do |(col, block), result|
66+
def defaulted_values
67+
@defaulted_values ||= @defaults.each_with_object({}) do |(col, block), result|
6868
next if @row.literal_values.key?(col)
6969
next if foreign_key_values.key?(col)
7070

71-
context = GeneratorContext.new(
71+
context = DefaultContext.new(
7272
record_name: @row.name,
7373
literal_values: @row.literal_values
7474
)

lib/fixturebot/row_definition.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
module FixtureBot
4+
class RowDefinition
5+
attr_reader :literal_values, :association_refs, :tag_refs
6+
7+
def initialize(table, schema)
8+
@literal_values = {}
9+
@association_refs = {}
10+
@tag_refs = {}
11+
12+
define_column_methods(table)
13+
define_association_methods(table)
14+
define_join_table_methods(table, schema)
15+
end
16+
17+
private
18+
19+
def define_column_methods(table)
20+
table.columns.each do |col|
21+
define_singleton_method(col) do |value|
22+
@literal_values[col] = value
23+
end
24+
end
25+
end
26+
27+
def define_association_methods(table)
28+
table.belongs_to_associations.each do |assoc|
29+
define_singleton_method(assoc.name) do |ref|
30+
@association_refs[assoc.name] = ref
31+
end
32+
end
33+
end
34+
35+
def define_join_table_methods(table, schema)
36+
schema.join_tables.each_value do |jt|
37+
if jt.left_table == table.name
38+
define_singleton_method(jt.right_table) do |*refs|
39+
@tag_refs[jt.name] = { table: jt.right_table, refs: refs }
40+
end
41+
elsif jt.right_table == table.name
42+
define_singleton_method(jt.left_table) do |*refs|
43+
@tag_refs[jt.name] = { table: jt.left_table, refs: refs }
44+
end
45+
end
46+
end
47+
end
48+
end
49+
end

0 commit comments

Comments
 (0)