Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/rom/associations/definitions/abstract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require "rom/initializer"
require "rom/relation/name"
require "rom/associations/through_identifier"
require "rom/support/inflector"

module ROM
module Associations
Expand Down Expand Up @@ -94,7 +95,12 @@ def self.process_options(target, options)
through = options[:through]

if through
options[:through] = ThroughIdentifier[through, target.relation, options[:assoc]]
options[:through] = ThroughIdentifier[
through,
target.relation,
options[:assoc],
inflector: options.fetch(:inflector, Inflector)
]
end

options[:name] = target.relation
Expand Down
8 changes: 4 additions & 4 deletions lib/rom/associations/through_identifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ class ThroughIdentifier
attr_reader :assoc_name

# @api private
def self.[](source, target, assoc_name = nil)
new(source, target, assoc_name || default_assoc_name(target))
def self.[](source, target, assoc_name = nil, inflector: Inflector)
new(source, target, assoc_name || default_assoc_name(target, inflector: inflector))
end

# @api private
def self.default_assoc_name(relation)
Inflector.singularize(relation).to_sym
def self.default_assoc_name(relation, inflector:)
inflector.singularize(relation).to_sym
end

# @api private
Expand Down
16 changes: 11 additions & 5 deletions lib/rom/command_compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def self.registry
# @return [Cache] local cache instance
option :cache, default: -> { Cache.new }

# @!attribute [r] inflector
# @return [Dry::Inflector] String inflector
# @api private
option :inflector, default: -> { Inflector }

# Return a specific command type for a given adapter and relation AST
#
# This class holds its own registry where all generated commands are being
Expand Down Expand Up @@ -102,7 +107,8 @@ def call(*args)
command = ROM::Commands::Graph.build(registry, graph_opts)

if command.graph?
CommandProxy.new(command)
root = inflector.singularize(command.name.relation).to_sym
CommandProxy.new(command, root)
elsif command.lazy?
command.unwrap
else
Expand All @@ -114,7 +120,7 @@ def call(*args)

# @api private
def type
@_type ||= Commands.const_get(Inflector.classify(id))[adapter]
@_type ||= Commands.const_get(inflector.classify(id))[adapter]
rescue NameError
nil
end
Expand All @@ -139,7 +145,7 @@ def visit_relation(node, parent_relation = nil)
if meta[:combine_type] == :many
name
else
{Inflector.singularize(name).to_sym => name}
{inflector.singularize(name).to_sym => name}
end

mapping =
Expand Down Expand Up @@ -190,7 +196,7 @@ def visit_attribute(*_args)
def register_command(rel_name, type, rel_meta, parent_relation = nil)
relation = relations[rel_name]

type.create_class(rel_name, type) do |klass|
type.create_class(rel_name, type, inflector: inflector) do |klass|
klass.result(rel_meta.fetch(:combine_type, result))

meta.each do |name, value|
Expand Down Expand Up @@ -237,7 +243,7 @@ def setup_associates(klass, relation, _meta, parent_relation)
if relation.associations.key?(parent_relation)
parent_relation
else
singular_name = Inflector.singularize(parent_relation).to_sym
singular_name = inflector.singularize(parent_relation).to_sym
singular_name if relation.associations.key?(singular_name)
end

Expand Down
8 changes: 5 additions & 3 deletions lib/rom/command_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ module ROM
#
# @api private
class CommandProxy
attr_reader :command, :root
attr_reader :command

attr_reader :root

# @api private
def initialize(command, root = Inflector.singularize(command.name.relation).to_sym)
def initialize(command, root)
@command = command
@root = root
end
Expand All @@ -23,7 +25,7 @@ def call(input)

# @api private
def >>(other)
self.class.new(command >> other)
self.class.new(command >> other, root)
end

# @api private
Expand Down
4 changes: 2 additions & 2 deletions lib/rom/commands/class_interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ def build(relation, **options)
# @return [Class, Object]
#
# @api public
def create_class(name, type, &block)
def create_class(name, type, inflector: Inflector, &block)
klass = Dry::Core::ClassBuilder
.new(name: "#{Inflector.classify(type)}[:#{name}]", parent: type)
.new(name: "#{inflector.classify(type)}[:#{name}]", parent: type)
.call

if block
Expand Down
3 changes: 2 additions & 1 deletion lib/rom/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require "rom/setup"
require "rom/configuration_dsl"
require "rom/support/notifications"
require "rom/support/inflector"

module ROM
class Configuration
Expand Down Expand Up @@ -38,7 +39,7 @@ class Configuration

def_delegators :@setup, :register_relation, :register_command, :register_mapper, :register_plugin,
:command_classes, :mapper_classes,
:auto_registration
:auto_registration, :inflector, :inflector=

def_delegators :@environment, :gateways, :gateways_map, :configure, :config

Expand Down
11 changes: 6 additions & 5 deletions lib/rom/configuration_dsl/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ class Command
# @api private
def self.build_class(name, relation, options = EMPTY_HASH, &block)
type = options.fetch(:type) { name }
command_type = Inflector.classify(type)
inflector = options.fetch(:inflector) { Inflector }
command_type = inflector.classify(type)
adapter = options.fetch(:adapter)
parent = ROM::Command.adapter_namespace(adapter).const_get(command_type)
class_name = generate_class_name(adapter, command_type, relation)
class_name = generate_class_name(adapter, command_type, relation, inflector)

Dry::Core::ClassBuilder.new(name: class_name, parent: parent).call do |klass|
klass.register_as(name)
Expand All @@ -31,11 +32,11 @@ def self.build_class(name, relation, options = EMPTY_HASH, &block)
# Create a command subclass name based on adapter, type and relation
#
# @api private
def self.generate_class_name(adapter, command_type, relation)
def self.generate_class_name(adapter, command_type, relation, inflector)
pieces = ["ROM"]
pieces << Inflector.classify(adapter)
pieces << inflector.classify(adapter)
pieces << "Commands"
pieces << "#{command_type}[#{Inflector.classify(relation)}s]"
pieces << "#{command_type}[#{inflector.classify(relation)}s]"
pieces.join("::")
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/rom/configuration_dsl/relation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class Relation
#
# @api private
def self.build_class(name, options = EMPTY_HASH)
class_name = "ROM::Relation[#{Inflector.camelize(name)}]"
inflector = options.fetch(:inflector) { Inflector }
class_name = "ROM::Relation[#{inflector.camelize(name)}]"
adapter = options.fetch(:adapter)

Dry::Core::ClassBuilder.new(name: class_name, parent: ROM::Relation[adapter]).call do |klass|
Expand Down
3 changes: 2 additions & 1 deletion lib/rom/create_container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ def finalize(environment, setup)
mappers: setup.mapper_classes,
plugins: setup.plugins,
notifications: setup.notifications,
config: environment.config.dup.freeze
config: environment.config.dup.freeze,
inflector: setup.inflector
)

finalize.run!
Expand Down
16 changes: 13 additions & 3 deletions lib/rom/relation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require "rom/constants"
require "rom/initializer"
require "rom/support/memoizable"
require "rom/support/inflector"

require "rom/relation/class_interface"

Expand Down Expand Up @@ -136,17 +137,26 @@ class Relation
# @api public
param :dataset

# @!attribute [r] inflector
# @return [Dry::Inflector] String inflector
# @api private
option :inflector, reader: true, default: -> { Inflector }

# @!attribute [r] schema
# @return [Schema] relation schema, defaults to class-level canonical
# schema (if it was defined) and sets an empty one as
# the fallback
# @api public
option :schema, default: -> { self.class.schema || self.class.default_schema }
option :schema, default: -> {
self.class.schema || self.class.default_schema(inflector: inflector)
}

# @!attribute [r] name
# @return [Object] The relation name
# @api public
option :name, default: -> { self.class.schema ? self.class.schema.name : self.class.default_name }
option :name, default: -> {
self.class.schema ? self.class.schema.name : self.class.default_name(inflector)
}

# @!attribute [r] input_schema
# @return [Object#[]] tuple processing function, uses schema or defaults to Hash[]
Expand Down Expand Up @@ -596,7 +606,7 @@ def foreign_key(name)
if attr
attr.name
else
:"#{Inflector.singularize(name.dataset)}_id"
:"#{inflector.singularize(name.dataset)}_id"
end
end

Expand Down
12 changes: 6 additions & 6 deletions lib/rom/relation/class_interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,14 @@ def schema(dataset = nil, as: nil, infer: false, &block)

@relation_name = Name[relation, ds_name]

@schema_proc = proc do |*args, &inner_block|
@schema_proc = proc do |**kwargs, &inner_block|
schema_dsl.new(
relation_name,
schema_class: schema_class,
attr_class: schema_attr_class,
inferrer: schema_inferrer.with(enabled: infer),
&block
).call(*args, &inner_block)
).call(**kwargs, &inner_block)
end
end
end
Expand Down Expand Up @@ -294,15 +294,15 @@ def schemas
# @return [Name]
#
# @api private
def default_name
Name[Inflector.underscore(name).tr("/", "_").to_sym]
def default_name(inflector = Inflector)
Name[inflector.underscore(name).tr("/", "_").to_sym]
end

# @api private
def default_schema(klass = self)
def default_schema(klass = self, inflector: Inflector)
klass.schema ||
if klass.schema_proc
klass.set_schema!(klass.schema_proc.call)
klass.set_schema!(klass.schema_proc.(inflector: inflector))
else
klass.schema_class.define(klass.default_name)
end
Expand Down
33 changes: 24 additions & 9 deletions lib/rom/schema/associations_dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,29 @@ class Schema
# This DSL is exposed in `associations do .. end` blocks in schema defintions.
#
# @api public
class AssociationsDSL < BasicObject
class AssociationsDSL < ::BasicObject
class << self
define_method(:const_missing, ::Object.method(:const_get))
end

include Associations::Definitions

# @!attribute [r] source
# @return [Relation::Name] The source relation
attr_reader :source

# @!attribute [r] inflector
# @return [Dry::Inflector] String inflector
attr_reader :inflector

# @!attribute [r] registry
# @return [RelationRegistry] Relations registry from a rom container
attr_reader :registry

# @api private
def initialize(source, &block)
def initialize(source, inflector = Inflector, &block)
@source = source
@inflector = inflector
@registry = {}
instance_exec(&block)
end
Expand Down Expand Up @@ -61,9 +72,9 @@ def initialize(source, &block)
# @api public
def one_to_many(target, **options)
if options[:through]
many_to_many(target, **options)
many_to_many(target, **options, inflector: inflector)
else
add(::ROM::Associations::Definitions::OneToMany.new(source, target, **options))
add(build(OneToMany, target, options))
end
end
alias_method :has_many, :one_to_many
Expand All @@ -88,7 +99,7 @@ def one_to_one(target, **options)
if options[:through]
one_to_one_through(target, **options)
else
add(::ROM::Associations::Definitions::OneToOne.new(source, target, **options))
add(build(OneToOne, target, options))
end
end

Expand All @@ -101,7 +112,7 @@ def one_to_one(target, **options)
#
# @api public
def one_to_one_through(target, **options)
add(::ROM::Associations::Definitions::OneToOneThrough.new(source, target, **options))
add(build(OneToOneThrough, target, options))
end

# Establish a many-to-many association
Expand All @@ -118,7 +129,7 @@ def one_to_one_through(target, **options)
#
# @api public
def many_to_many(target, **options)
add(::ROM::Associations::Definitions::ManyToMany.new(source, target, **options))
add(build(ManyToMany, target, options))
end

# Establish a many-to-one association
Expand All @@ -135,7 +146,7 @@ def many_to_many(target, **options)
#
# @api public
def many_to_one(target, **options)
add(::ROM::Associations::Definitions::ManyToOne.new(source, target, **options))
add(build(ManyToOne, target, options))
end

# Shortcut for many_to_one which sets alias automatically
Expand Down Expand Up @@ -183,6 +194,10 @@ def call

private

def build(definition, target, options)
definition.new(source, target, **options, inflector: inflector)
end

# @api private
def add(association)
key = association.as || association.name
Expand All @@ -199,7 +214,7 @@ def add(association)

# @api private
def dataset_name(name)
Inflector.pluralize(name).to_sym
inflector.pluralize(name).to_sym
end
end
end
Expand Down
Loading