rom 0.9.1 → 1.0.0.beta1

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +30 -12
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG.md +24 -0
  5. data/Gemfile +7 -3
  6. data/README.md +24 -11
  7. data/lib/rom.rb +9 -26
  8. data/lib/rom/command.rb +113 -75
  9. data/lib/rom/commands/class_interface.rb +115 -0
  10. data/lib/rom/commands/graph.rb +17 -23
  11. data/lib/rom/commands/graph/builder.rb +176 -0
  12. data/lib/rom/commands/graph/class_interface.rb +8 -2
  13. data/lib/rom/commands/graph/input_evaluator.rb +13 -9
  14. data/lib/rom/commands/lazy.rb +23 -17
  15. data/lib/rom/commands/lazy/create.rb +23 -0
  16. data/lib/rom/commands/lazy/delete.rb +27 -0
  17. data/lib/rom/commands/lazy/update.rb +34 -0
  18. data/lib/rom/commands/result.rb +14 -0
  19. data/lib/rom/commands/update.rb +0 -4
  20. data/lib/rom/configuration.rb +86 -0
  21. data/lib/rom/{setup_dsl/setup.rb → configuration_dsl.rb} +9 -7
  22. data/lib/rom/configuration_dsl/command.rb +43 -0
  23. data/lib/rom/{setup_dsl → configuration_dsl}/command_dsl.rb +5 -4
  24. data/lib/rom/configuration_dsl/mapper.rb +37 -0
  25. data/lib/rom/{setup_dsl → configuration_dsl}/mapper_dsl.rb +11 -5
  26. data/lib/rom/configuration_dsl/relation.rb +26 -0
  27. data/lib/rom/configuration_plugin.rb +17 -0
  28. data/lib/rom/constants.rb +5 -12
  29. data/lib/rom/container.rb +11 -8
  30. data/lib/rom/create_container.rb +61 -0
  31. data/lib/rom/environment.rb +27 -241
  32. data/lib/rom/gateway.rb +18 -2
  33. data/lib/rom/global.rb +24 -0
  34. data/lib/rom/global/plugin_dsl.rb +2 -0
  35. data/lib/rom/lint/spec.rb +0 -12
  36. data/lib/rom/lint/test.rb +0 -31
  37. data/lib/rom/memory/commands.rb +2 -2
  38. data/lib/rom/memory/gateway.rb +2 -0
  39. data/lib/rom/pipeline.rb +1 -1
  40. data/lib/rom/plugin_base.rb +1 -1
  41. data/lib/rom/plugin_registry.rb +12 -10
  42. data/lib/rom/plugins/configuration/configuration_dsl.rb +16 -0
  43. data/lib/rom/plugins/relation/key_inference.rb +31 -0
  44. data/lib/rom/plugins/relation/view.rb +90 -0
  45. data/lib/rom/plugins/relation/view/dsl.rb +32 -0
  46. data/lib/rom/relation.rb +1 -11
  47. data/lib/rom/relation/class_interface.rb +37 -50
  48. data/lib/rom/setup.rb +13 -104
  49. data/lib/rom/setup/auto_registration.rb +55 -0
  50. data/lib/rom/setup/finalize.rb +113 -127
  51. data/lib/rom/setup/finalize/commands.rb +67 -0
  52. data/lib/rom/setup/finalize/mappers.rb +36 -0
  53. data/lib/rom/setup/finalize/relations.rb +53 -0
  54. data/lib/rom/support/configurable.rb +21 -7
  55. data/lib/rom/version.rb +1 -1
  56. data/rakelib/mutant.rake +4 -1
  57. data/rom.gemspec +3 -4
  58. data/spec/fixtures/app/commands/create_user.rb +2 -0
  59. data/spec/fixtures/app/mappers/user_list.rb +2 -0
  60. data/spec/fixtures/app/relations/users.rb +2 -0
  61. data/spec/fixtures/lib/persistence/commands/create_user.rb +6 -0
  62. data/spec/fixtures/lib/persistence/mappers/user_list.rb +6 -0
  63. data/spec/fixtures/lib/persistence/relations/users.rb +6 -0
  64. data/spec/{unit/rom → integration}/command_registry_spec.rb +8 -9
  65. data/spec/integration/commands/create_spec.rb +17 -13
  66. data/spec/integration/commands/delete_spec.rb +12 -11
  67. data/spec/integration/commands/error_handling_spec.rb +5 -4
  68. data/spec/integration/commands/graph_builder_spec.rb +213 -0
  69. data/spec/integration/commands/graph_spec.rb +112 -49
  70. data/spec/integration/commands/update_spec.rb +14 -11
  71. data/spec/integration/commands_spec.rb +60 -0
  72. data/spec/integration/mappers/combine_spec.rb +7 -6
  73. data/spec/integration/mappers/deep_embedded_spec.rb +5 -6
  74. data/spec/integration/mappers/definition_dsl_spec.rb +19 -18
  75. data/spec/integration/mappers/embedded_spec.rb +11 -12
  76. data/spec/integration/mappers/exclude_spec.rb +5 -6
  77. data/spec/integration/mappers/fold_spec.rb +8 -7
  78. data/spec/integration/mappers/group_spec.rb +16 -15
  79. data/spec/integration/mappers/overwrite_attributes_value_spec.rb +5 -5
  80. data/spec/integration/mappers/prefix_separator_spec.rb +5 -7
  81. data/spec/integration/mappers/prefix_spec.rb +5 -7
  82. data/spec/integration/mappers/prefixing_attributes_spec.rb +7 -7
  83. data/spec/integration/mappers/registering_custom_mappers_spec.rb +4 -5
  84. data/spec/integration/mappers/renaming_attributes_spec.rb +18 -18
  85. data/spec/integration/mappers/step_spec.rb +11 -12
  86. data/spec/integration/mappers/symbolizing_attributes_spec.rb +11 -8
  87. data/spec/integration/mappers/unfold_spec.rb +9 -10
  88. data/spec/integration/mappers/ungroup_spec.rb +10 -11
  89. data/spec/integration/mappers/unwrap_spec.rb +10 -15
  90. data/spec/integration/mappers/wrap_spec.rb +16 -15
  91. data/spec/{unit/rom → integration}/memory/commands/create_spec.rb +7 -5
  92. data/spec/{unit/rom → integration}/memory/commands/delete_spec.rb +7 -5
  93. data/spec/{unit/rom → integration}/memory/commands/update_spec.rb +7 -5
  94. data/spec/integration/multi_env_spec.rb +16 -124
  95. data/spec/integration/multi_repo_spec.rb +9 -9
  96. data/spec/integration/relations/default_dataset_spec.rb +15 -0
  97. data/spec/integration/relations/inheritance_spec.rb +5 -7
  98. data/spec/integration/relations/reading_spec.rb +32 -65
  99. data/spec/integration/relations/registry_dsl_spec.rb +5 -4
  100. data/spec/integration/repositories/extending_relations_spec.rb +6 -7
  101. data/spec/integration/repositories/setting_logger_spec.rb +5 -7
  102. data/spec/integration/setup_spec.rb +49 -61
  103. data/spec/shared/command_graph.rb +50 -0
  104. data/spec/shared/container.rb +9 -0
  105. data/spec/shared/gateway_only.rb +6 -0
  106. data/spec/shared/no_container.rb +16 -0
  107. data/spec/shared/one_behavior.rb +4 -4
  108. data/spec/shared/users_and_tasks.rb +5 -17
  109. data/spec/spec_helper.rb +5 -3
  110. data/spec/test/memory_repository_lint_test.rb +1 -1
  111. data/spec/unit/rom/auto_registration_spec.rb +54 -0
  112. data/spec/unit/rom/commands/graph_spec.rb +18 -44
  113. data/spec/unit/rom/commands/lazy_spec.rb +246 -35
  114. data/spec/unit/rom/commands/result_spec.rb +56 -0
  115. data/spec/unit/rom/commands_spec.rb +9 -73
  116. data/spec/unit/rom/configurable_spec.rb +49 -0
  117. data/spec/unit/rom/configuration_spec.rb +61 -0
  118. data/spec/unit/rom/container_spec.rb +39 -33
  119. data/spec/unit/rom/create_container_spec.rb +151 -0
  120. data/spec/unit/rom/environment_spec.rb +123 -0
  121. data/spec/unit/rom/gateway_spec.rb +58 -2
  122. data/spec/unit/rom/global_spec.rb +10 -7
  123. data/spec/unit/rom/plugin_spec.rb +44 -25
  124. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +27 -0
  125. data/spec/unit/rom/plugins/relation/view_spec.rb +47 -0
  126. data/spec/unit/rom/relation/composite_spec.rb +20 -20
  127. data/spec/unit/rom/relation/curried_spec.rb +10 -11
  128. data/spec/unit/rom/relation/graph_spec.rb +27 -27
  129. data/spec/unit/rom/relation/lazy/combine_spec.rb +26 -20
  130. data/spec/unit/rom/relation/lazy_spec.rb +38 -38
  131. data/spec/unit/rom/relation/loaded_spec.rb +2 -3
  132. data/spec/unit/rom/relation_spec.rb +39 -2
  133. metadata +58 -66
  134. data/lib/rom/commands/abstract.rb +0 -184
  135. data/lib/rom/environment_plugin.rb +0 -17
  136. data/lib/rom/environment_plugins/auto_registration.rb +0 -38
  137. data/lib/rom/repository.rb +0 -16
  138. data/lib/rom/setup_dsl/command.rb +0 -36
  139. data/lib/rom/setup_dsl/mapper.rb +0 -32
  140. data/lib/rom/setup_dsl/relation.rb +0 -30
  141. data/spec/integration/inline_setup_spec.rb +0 -65
  142. data/spec/unit/rom/repository_spec.rb +0 -12
  143. data/spec/unit/rom/setup_spec.rb +0 -253
@@ -0,0 +1,23 @@
1
+ module ROM
2
+ module Commands
3
+ class Lazy
4
+ class Create < Lazy
5
+ def call(*args)
6
+ first = args.first
7
+ last = args.last
8
+ size = args.size
9
+
10
+ if size > 1 && last.is_a?(Array)
11
+ last.map.with_index do |parent, index|
12
+ children = evaluator.call(first, index)
13
+ command_proc[command, parent, children].call(children, parent)
14
+ end.reduce(:concat)
15
+ else
16
+ input = evaluator.call(first)
17
+ command.call(input, *args[1..size-1])
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module ROM
2
+ module Commands
3
+ class Lazy
4
+ class Delete < Lazy
5
+ def call(*args)
6
+ first = args.first
7
+ last = args.last
8
+ size = args.size
9
+
10
+ if size > 1 && last.is_a?(Array)
11
+ raise NotImplementedError
12
+ else
13
+ input = evaluator.call(first)
14
+
15
+ if input.is_a?(Array)
16
+ input.map do |item|
17
+ command_proc[command, *(size > 1 ? [last, item] : [input])].call
18
+ end
19
+ else
20
+ command_proc[command, input].call
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ module ROM
2
+ module Commands
3
+ class Lazy
4
+ class Update < Lazy
5
+ def call(*args)
6
+ first = args.first
7
+ last = args.last
8
+ size = args.size
9
+
10
+ if size > 1 && last.is_a?(Array)
11
+ last.map.with_index do |parent, index|
12
+ children = evaluator.call(first, index)
13
+
14
+ children.map do |child|
15
+ command_proc[command, parent, child].call(child, parent)
16
+ end
17
+ end.reduce(:concat)
18
+ else
19
+ input = evaluator.call(first)
20
+
21
+ if input.is_a?(Array)
22
+ input.map.with_index do |item, index|
23
+ command_proc[command, last, item].call(item, *args[1..size-1])
24
+ end
25
+ else
26
+ command_proc[command, *(size > 1 ? [last, input] : [input])]
27
+ .call(input, *args[1..size-1])
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -24,6 +24,20 @@ module ROM
24
24
  end
25
25
  alias_method :to_a, :to_ary
26
26
 
27
+ # Return true if command successful
28
+ #
29
+ # @api public
30
+ def success?
31
+ is_a?(Success)
32
+ end
33
+
34
+ # Return true if command failed
35
+ #
36
+ # @api public
37
+ def failure?
38
+ is_a?(Failure)
39
+ end
40
+
27
41
  # Success result has a value and no error
28
42
  #
29
43
  # @api public
@@ -1,5 +1,4 @@
1
1
  require 'rom/command'
2
- require 'rom/support/deprecations'
3
2
 
4
3
  module ROM
5
4
  module Commands
@@ -9,14 +8,11 @@ module ROM
9
8
  #
10
9
  # @abstract
11
10
  class Update < Command
12
- extend Deprecations
13
-
14
11
  # @see AbstractCommand#call
15
12
  def call(*args)
16
13
  assert_tuple_count
17
14
  super
18
15
  end
19
- deprecate :set, :call
20
16
  end
21
17
  end
22
18
  end
@@ -0,0 +1,86 @@
1
+ require 'rom/environment'
2
+ require 'rom/setup'
3
+
4
+ module ROM
5
+ class Configuration
6
+ extend Forwardable
7
+
8
+ NoDefaultAdapterError = Class.new(StandardError)
9
+
10
+ attr_reader :environment, :setup
11
+
12
+ def_delegators :@setup, :register_relation, :register_command, :register_mapper,
13
+ :relation_classes, :command_classes, :mapper_classes,
14
+ :auto_registration
15
+
16
+ def_delegators :@environment, :gateways, :gateways_map, :configure, :config
17
+
18
+ # @api public
19
+ def initialize(*args, &block)
20
+ @environment = Environment.new(*args)
21
+ @setup = Setup.new
22
+
23
+ block.call(self) unless block.nil?
24
+ end
25
+
26
+ # Apply a plugin to the configuration
27
+ #
28
+ # @param [Mixed] The plugin identifier, usually a Symbol
29
+ # @param [Hash] Plugin options
30
+ #
31
+ # @api public
32
+ def use(plugin, options = {})
33
+ if plugin.is_a?(Array)
34
+ plugin.each { |p| use(p) }
35
+ elsif plugin.is_a?(Hash)
36
+ plugin.to_a.each { |p| use(*p) }
37
+ else
38
+ ROM.plugin_registry.configuration.fetch(plugin).apply_to(self, options)
39
+ end
40
+
41
+ self
42
+ end
43
+
44
+ # Return gateway identified by name
45
+ #
46
+ # @return [Gateway]
47
+ #
48
+ # @api private
49
+ def [](name)
50
+ gateways.fetch(name)
51
+ end
52
+
53
+ # Returns gateway if method is a name of a registered gateway
54
+ #
55
+ # @return [Gateway]
56
+ #
57
+ # @api private
58
+ def method_missing(name, *)
59
+ gateways.fetch(name) { super }
60
+ end
61
+
62
+ # Hook for respond_to? used internally
63
+ #
64
+ # @api private
65
+ def respond_to?(name, include_all=false)
66
+ gateways.has_key?(name) || super
67
+ end
68
+
69
+ # @api private
70
+ def default_gateway
71
+ @default_gateway ||= gateways[:default]
72
+ end
73
+
74
+ # @api private
75
+ def adapter_for_gateway(gateway)
76
+ ROM.adapters.select do |key, value|
77
+ value.const_defined?(:Gateway) && gateway.kind_of?(value.const_get(:Gateway))
78
+ end.keys.first
79
+ end
80
+
81
+ # @api private
82
+ def default_adapter
83
+ @default_adapter ||= adapter_for_gateway(default_gateway) || ROM.adapters.keys.first
84
+ end
85
+ end
86
+ end
@@ -1,13 +1,14 @@
1
- require 'rom/setup_dsl/relation'
1
+ require 'rom/support/constants'
2
2
 
3
- require 'rom/setup_dsl/mapper_dsl'
4
- require 'rom/setup_dsl/command_dsl'
3
+ require 'rom/configuration_dsl/relation'
4
+ require 'rom/configuration_dsl/mapper_dsl'
5
+ require 'rom/configuration_dsl/command_dsl'
5
6
 
6
7
  module ROM
7
- # This extends Setup class with the DSL methods
8
+ # This extends Configuration class with the DSL methods
8
9
  #
9
10
  # @api public
10
- class Setup
11
+ module ConfigurationDSL
11
12
  # Relation definition DSL
12
13
  #
13
14
  # @example
@@ -24,6 +25,7 @@ module ROM
24
25
  klass = Relation.build_class(name, klass_opts)
25
26
  klass.register_as(name)
26
27
  klass.class_eval(&block) if block
28
+ register_relation(klass)
27
29
  klass
28
30
  end
29
31
 
@@ -43,7 +45,7 @@ module ROM
43
45
  #
44
46
  # @api public
45
47
  def mappers(&block)
46
- MapperDSL.new(self, &block)
48
+ register_mapper(*MapperDSL.new(self, mapper_classes, block).mapper_classes)
47
49
  end
48
50
 
49
51
  # Command definition DSL
@@ -70,7 +72,7 @@ module ROM
70
72
  #
71
73
  # @api public
72
74
  def commands(name, &block)
73
- CommandDSL.new(name, default_adapter, &block)
75
+ register_command(*CommandDSL.new(name, default_adapter, &block).command_classes)
74
76
  end
75
77
  end
76
78
  end
@@ -0,0 +1,43 @@
1
+ require 'rom/support/constants'
2
+
3
+ require 'rom/support/inflector'
4
+ require 'rom/support/class_builder'
5
+
6
+ module ROM
7
+ module ConfigurationDSL
8
+ # Setup DSL-specific command extensions
9
+ #
10
+ # @private
11
+ class Command
12
+ # Generate a command subclass
13
+ #
14
+ # This is used by Setup#commands DSL and its `define` block
15
+ #
16
+ # @api private
17
+ def self.build_class(name, relation, options = EMPTY_HASH, &block)
18
+ type = options.fetch(:type) { name }
19
+ command_type = Inflector.classify(type)
20
+ adapter = options.fetch(:adapter)
21
+ parent = ROM::Command.adapter_namespace(adapter).const_get(command_type)
22
+ class_name = generate_class_name(adapter, command_type, relation)
23
+
24
+ ClassBuilder.new(name: class_name, parent: parent).call do |klass|
25
+ klass.register_as(name)
26
+ klass.relation(relation)
27
+ klass.class_eval(&block) if block
28
+ end
29
+ end
30
+
31
+ # Create a command subclass name based on adapter, type and relation
32
+ #
33
+ # @api private
34
+ def self.generate_class_name(adapter, command_type, relation)
35
+ pieces = ['ROM']
36
+ pieces << Inflector.classify(adapter)
37
+ pieces << 'Commands'
38
+ pieces << "#{command_type}[#{Inflector.classify(relation)}s]"
39
+ pieces.join('::')
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,17 +1,18 @@
1
- require 'rom/setup_dsl/command'
1
+ require 'rom/configuration_dsl/command'
2
2
 
3
3
  module ROM
4
- class Setup
4
+ module ConfigurationDSL
5
5
  # Command `define` DSL used by Setup#commands
6
6
  #
7
7
  # @private
8
8
  class CommandDSL
9
- attr_reader :relation, :adapter
9
+ attr_reader :relation, :adapter, :command_classes
10
10
 
11
11
  # @api private
12
12
  def initialize(relation, adapter = nil, &block)
13
13
  @relation = relation
14
14
  @adapter = adapter
15
+ @command_classes = []
15
16
  instance_exec(&block)
16
17
  end
17
18
 
@@ -25,7 +26,7 @@ module ROM
25
26
  #
26
27
  # @api public
27
28
  def define(name, options = EMPTY_HASH, &block)
28
- Command.build_class(
29
+ @command_classes << Command.build_class(
29
30
  name, relation, { adapter: adapter }.merge(options), &block
30
31
  )
31
32
  end
@@ -0,0 +1,37 @@
1
+ require 'rom/support/constants'
2
+ require 'rom/support/class_builder'
3
+
4
+ module ROM
5
+ module ConfigurationDSL
6
+ # Setup DSL-specific mapper extensions
7
+ #
8
+ # @private
9
+ class Mapper
10
+ # Generate a mapper subclass
11
+ #
12
+ # This is used by Setup#mappers DSL
13
+ #
14
+ # @api private
15
+ def self.build_class(name, mapper_registry, options = EMPTY_HASH, &block)
16
+ class_name = "ROM::Mapper[#{name}]"
17
+
18
+ parent = options[:parent]
19
+ inherit_header = options.fetch(:inherit_header) { ROM::Mapper.inherit_header }
20
+
21
+ parent_class =
22
+ if parent
23
+ mapper_registry.detect { |klass| klass.relation == parent }
24
+ else
25
+ ROM::Mapper
26
+ end
27
+
28
+ ClassBuilder.new(name: class_name, parent: parent_class).call do |klass|
29
+ klass.relation(name)
30
+ klass.inherit_header(inherit_header)
31
+
32
+ klass.class_eval(&block) if block
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,17 +1,23 @@
1
- require 'rom/setup_dsl/mapper'
1
+ require 'rom/support/constants'
2
+ require 'rom/configuration_dsl/mapper'
2
3
 
3
4
  module ROM
4
- class Setup
5
+ module ConfigurationDSL
5
6
  # Mapper definition DSL used by Setup DSL
6
7
  #
7
8
  # @private
8
9
  class MapperDSL
9
- attr_reader :registry
10
+ attr_reader :registry, :mapper_classes, :mapper_classes
10
11
 
11
12
  # @api private
12
- def initialize(registry, &block)
13
+ def initialize(registry, mapper_classes, block)
13
14
  @registry = registry
15
+ @mapper_classes = mapper_classes
16
+ @defined_mappers = []
17
+
14
18
  instance_exec(&block)
19
+
20
+ @mapper_classes = @defined_mappers
15
21
  end
16
22
 
17
23
  # Define a mapper class
@@ -23,7 +29,7 @@ module ROM
23
29
  #
24
30
  # @api public
25
31
  def define(name, options = EMPTY_HASH, &block)
26
- Mapper.build_class(name, options, &block)
32
+ @defined_mappers << Mapper.build_class(name, (@mapper_classes + @defined_mappers), options, &block)
27
33
  self
28
34
  end
29
35
 
@@ -0,0 +1,26 @@
1
+ require 'rom/support/constants'
2
+ require 'rom/support/class_builder'
3
+
4
+ module ROM
5
+ module ConfigurationDSL
6
+ # Setup DSL-specific relation extensions
7
+ #
8
+ # @private
9
+ class Relation
10
+ # Generate a relation subclass
11
+ #
12
+ # This is used by Setup#relation DSL
13
+ #
14
+ # @api private
15
+ def self.build_class(name, options = EMPTY_HASH)
16
+ class_name = "ROM::Relation[#{Inflector.camelize(name)}]"
17
+ adapter = options.fetch(:adapter)
18
+
19
+ ClassBuilder.new(name: class_name, parent: ROM::Relation[adapter]).call do |klass|
20
+ klass.gateway(options.fetch(:gateway, :default))
21
+ klass.dataset(name)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ require 'rom/plugin_base'
2
+
3
+ module ROM
4
+ # ConfigurationPlugin is a simple object used to store configuration plugin configurations
5
+ #
6
+ # @private
7
+ class ConfigurationPlugin < PluginBase
8
+ # Apply this plugin to the provided configuration
9
+ #
10
+ # @param [ROM::Configuration] configuration
11
+ #
12
+ # @api private
13
+ def apply_to(configuration, options = {})
14
+ mod.apply(configuration, options)
15
+ end
16
+ end
17
+ end