rom 0.9.1 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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