rom 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +5 -8
  4. data/CHANGELOG.md +28 -1
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +2 -2
  7. data/lib/rom.rb +1 -1
  8. data/lib/rom/command.rb +7 -5
  9. data/lib/rom/command_registry.rb +1 -1
  10. data/lib/rom/commands.rb +0 -2
  11. data/lib/rom/commands/abstract.rb +55 -25
  12. data/lib/rom/commands/composite.rb +13 -1
  13. data/lib/rom/commands/delete.rb +0 -8
  14. data/lib/rom/commands/graph.rb +102 -0
  15. data/lib/rom/commands/graph/class_interface.rb +69 -0
  16. data/lib/rom/commands/lazy.rb +87 -0
  17. data/lib/rom/constants.rb +22 -0
  18. data/lib/rom/env.rb +48 -18
  19. data/lib/rom/gateway.rb +132 -0
  20. data/lib/rom/global.rb +19 -19
  21. data/lib/rom/header.rb +42 -16
  22. data/lib/rom/header/attribute.rb +37 -15
  23. data/lib/rom/lint/gateway.rb +94 -0
  24. data/lib/rom/lint/spec.rb +15 -3
  25. data/lib/rom/lint/test.rb +45 -14
  26. data/lib/rom/mapper.rb +23 -10
  27. data/lib/rom/mapper/attribute_dsl.rb +157 -18
  28. data/lib/rom/memory.rb +1 -1
  29. data/lib/rom/memory/commands.rb +10 -8
  30. data/lib/rom/memory/dataset.rb +22 -2
  31. data/lib/rom/memory/{repository.rb → gateway.rb} +10 -10
  32. data/lib/rom/pipeline.rb +2 -1
  33. data/lib/rom/processor/transproc.rb +105 -14
  34. data/lib/rom/relation.rb +4 -4
  35. data/lib/rom/relation/class_interface.rb +19 -13
  36. data/lib/rom/relation/graph.rb +22 -0
  37. data/lib/rom/relation/lazy.rb +5 -3
  38. data/lib/rom/repository.rb +9 -118
  39. data/lib/rom/setup.rb +21 -14
  40. data/lib/rom/setup/finalize.rb +19 -19
  41. data/lib/rom/setup_dsl/relation.rb +10 -1
  42. data/lib/rom/support/deprecations.rb +21 -3
  43. data/lib/rom/support/enumerable_dataset.rb +1 -1
  44. data/lib/rom/version.rb +1 -1
  45. data/rom.gemspec +2 -4
  46. data/spec/integration/commands/delete_spec.rb +6 -0
  47. data/spec/integration/commands/graph_spec.rb +235 -0
  48. data/spec/integration/mappers/combine_spec.rb +14 -5
  49. data/spec/integration/mappers/definition_dsl_spec.rb +6 -1
  50. data/spec/integration/mappers/exclude_spec.rb +28 -0
  51. data/spec/integration/mappers/fold_spec.rb +16 -0
  52. data/spec/integration/mappers/group_spec.rb +0 -22
  53. data/spec/integration/mappers/prefix_separator_spec.rb +54 -0
  54. data/spec/integration/mappers/prefix_spec.rb +50 -0
  55. data/spec/integration/mappers/reusing_mappers_spec.rb +21 -0
  56. data/spec/integration/mappers/step_spec.rb +120 -0
  57. data/spec/integration/mappers/unfold_spec.rb +93 -0
  58. data/spec/integration/mappers/ungroup_spec.rb +127 -0
  59. data/spec/integration/mappers/unwrap_spec.rb +2 -2
  60. data/spec/integration/multi_repo_spec.rb +11 -11
  61. data/spec/integration/repositories/setting_logger_spec.rb +2 -2
  62. data/spec/integration/setup_spec.rb +11 -1
  63. data/spec/shared/command_behavior.rb +18 -0
  64. data/spec/shared/materializable.rb +4 -2
  65. data/spec/shared/users_and_tasks.rb +3 -3
  66. data/spec/test/memory_repository_lint_test.rb +4 -4
  67. data/spec/unit/rom/commands/graph_spec.rb +198 -0
  68. data/spec/unit/rom/commands/lazy_spec.rb +88 -0
  69. data/spec/unit/rom/commands_spec.rb +2 -2
  70. data/spec/unit/rom/env_spec.rb +26 -0
  71. data/spec/unit/rom/gateway_spec.rb +90 -0
  72. data/spec/unit/rom/global_spec.rb +4 -3
  73. data/spec/unit/rom/mapper/dsl_spec.rb +42 -1
  74. data/spec/unit/rom/mapper_spec.rb +4 -1
  75. data/spec/unit/rom/memory/commands/create_spec.rb +21 -0
  76. data/spec/unit/rom/memory/commands/delete_spec.rb +21 -0
  77. data/spec/unit/rom/memory/commands/update_spec.rb +21 -0
  78. data/spec/unit/rom/memory/relation_spec.rb +42 -10
  79. data/spec/unit/rom/memory/repository_spec.rb +3 -3
  80. data/spec/unit/rom/processor/transproc_spec.rb +75 -0
  81. data/spec/unit/rom/relation/lazy/combine_spec.rb +33 -4
  82. data/spec/unit/rom/relation/lazy_spec.rb +9 -1
  83. data/spec/unit/rom/repository_spec.rb +4 -63
  84. data/spec/unit/rom/setup_spec.rb +19 -5
  85. metadata +28 -38
  86. data/.ruby-version +0 -1
  87. data/lib/rom/lint/repository.rb +0 -94
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fef04bd27871ee67a85b39c0cfb4a2a9c588a01f
4
- data.tar.gz: 6f5e0515a4cdd8d0df9816c574bf176aa9634783
3
+ metadata.gz: 1f71a2cbfa094787fbd2ca709cd2c229aca10799
4
+ data.tar.gz: 73f461e9a6e50aec0d632f4332137fc389d57a70
5
5
  SHA512:
6
- metadata.gz: 9ea6324c33c9c7701ab5452f291d7c397e41062ea706c2345c66d167b9cad8e7914f39af536fa065cb76e3bdca612898bc89de9e0fa6d46a1e58a4c532b88576
7
- data.tar.gz: 9954ad8c0413dc7e94d4170703b47dd3a80387a22236c37a86d71ce7b6a01b8588658673a0cd10224013cf7b166c6592f800585f5c2fa4ecc691825701d3dcb0
6
+ metadata.gz: a74fec1aaf8c1d5f0feb8b2128fa4db3c0ec31cf7018f8905ef396e3a614d071f17d7f60f2bd3411ca887efdbb9959faa3e73f0082fa3cbedcf43a95efd93286
7
+ data.tar.gz: 1ad96805142be1ac15bb329109e251c8c4170ce2c42f6fc409b7351899bb8ae283686241b414a7f1ff1bb08dc4b1b10f0ff59da2ad4e0d46f2e3c8e90f1dbf62
data/.gitignore CHANGED
@@ -20,3 +20,4 @@ vendor/
20
20
  .yardoc
21
21
  _yardoc
22
22
  doc/
23
+ .ruby-version
data/.rubocop.yml CHANGED
@@ -5,6 +5,7 @@ inherit_from: .rubocop_todo.yml
5
5
  AllCops:
6
6
  Exclude:
7
7
  - tmp/**/*
8
+ - vendor/**/*
8
9
 
9
10
  Style/BlockDelimiters:
10
11
  EnforcedStyle: semantic
@@ -35,10 +36,6 @@ Style/AlignParameters:
35
36
  Style/AsciiComments:
36
37
  Enabled: false
37
38
 
38
- # Allow using braces for value-returning blocks
39
- Style/Blocks:
40
- Enabled: false
41
-
42
39
  # Documentation checked by Inch CI
43
40
  Style/Documentation:
44
41
  Enabled: false
@@ -55,15 +52,15 @@ Style/Lambda:
55
52
  Style/MultilineBlockChain:
56
53
  Enabled: false
57
54
 
55
+ # Multiline operation chains are indented
56
+ Style/MultilineOperationIndentation:
57
+ EnforcedStyle: indented
58
+
58
59
  # Result::Success and Result::Failure use > for callbacks
59
60
  Style/OpMethod:
60
61
  Exclude:
61
62
  - lib/rom/command_registry.rb
62
63
 
63
- # Even a single escaped slash can be confusing
64
- Style/RegexpLiteral:
65
- MaxSlashes: 0
66
-
67
64
  # Don’t introduce semantic fail/raise distinction
68
65
  Style/SignalException:
69
66
  EnforcedStyle: only_raise
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ ## v0.8.0 2015-06-22
2
+
3
+ ### Added
4
+
5
+ * New `step` mapper operation that allows multistep transformations inside a single mapper (dekz)
6
+ * New `ungroup` and `unfold` mapper operations inverse `group` and `fold` (nepalez)
7
+ * Support deep nesting of `unwrap` mapper operations (nepalez)
8
+ * Support usage of `exclude` in a root of the mapper (nepalez)
9
+ * Support usage of `prefix` and `prefix_separator` mapper operations inside blocks (nepalez)
10
+ * Support renaming of the rest of an attribute after `unwrap` (nepalez)
11
+
12
+ ### Changed
13
+
14
+ * `Repository` class has been renamed to `Gateway` with proper deprecation
15
+ warnings (cflipse)
16
+ * `combine` in mapper can be used without a block (kwando)
17
+ * `wrap` and `group` in mapper will raise error if `:mapper` is set along with
18
+ block or options (vrish88)
19
+
20
+ ### Fixed
21
+
22
+ * `order` memory repository operation sorts tuples containing empty values (nepalez)
23
+ * `Mapper::AttributeDSL#embedded` now honors `option[:type]` when used
24
+ with `option[:mapper]` (c0)
25
+
26
+ [Compare v0.7.1...v0.8.0](https://github.com/rom-rb/rom/compare/v0.7.1...v0.8.0)
27
+
1
28
  ## v0.7.1 2015-05-22
2
29
 
3
30
  ### Added
@@ -14,7 +41,7 @@
14
41
  * [rom/memory] `restrict` operation supports array as a value (gotar)
15
42
  * [rom/memory] `restrict` operation supports regexp as a value (gotar)
16
43
 
17
- [Compare v0.7.0...HEAD](https://github.com/rom-rb/rom/compare/v0.7.0...HEAD)
44
+ [Compare v0.7.0...v0.7.1](https://github.com/rom-rb/rom/compare/v0.7.0...v0.7.1)
18
45
 
19
46
  ## v0.7.0 2015-05-17
20
47
 
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile CHANGED
@@ -34,7 +34,7 @@ group :benchmarks do
34
34
  end
35
35
 
36
36
  group :tools do
37
- gem 'rubocop'
37
+ gem 'rubocop', '~> 0.31'
38
38
 
39
39
  gem 'guard'
40
40
  gem 'guard-rspec'
@@ -43,7 +43,7 @@ group :tools do
43
43
  gem 'byebug'
44
44
 
45
45
  platform :mri do
46
- gem 'mutant', '>= 0.7.7'
46
+ gem 'mutant', '>= 0.8.0', github: 'mbj/mutant', branch: 'master'
47
47
  gem 'mutant-rspec'
48
48
  end
49
49
  end
data/lib/rom.rb CHANGED
@@ -14,7 +14,7 @@ require 'rom/support/class_builder'
14
14
  require 'rom/plugin'
15
15
  require 'rom/relation'
16
16
  require 'rom/mapper'
17
- require 'rom/command'
17
+ require 'rom/commands'
18
18
 
19
19
  # default mapper processor using Transproc gem
20
20
  require 'rom/processor/transproc'
data/lib/rom/command.rb CHANGED
@@ -50,6 +50,8 @@ module ROM
50
50
  # @api private
51
51
  def self.adapter_namespace(adapter)
52
52
  ROM.adapters.fetch(adapter).const_get(:Commands)
53
+ rescue KeyError
54
+ raise AdapterNotPresentError.new(adapter, :relation)
53
55
  end
54
56
 
55
57
  # Build a command class for a specific relation with options
@@ -84,20 +86,20 @@ module ROM
84
86
  # @option options [Symbol] :adapter (:default) first adapter to check for plugin
85
87
  #
86
88
  # @api public
87
- def self.use(plugin, options = {})
89
+ def self.use(plugin, _options = {})
88
90
  ROM.plugin_registry.commands.fetch(plugin, adapter).apply_to(self)
89
91
  end
90
92
 
91
93
  # Build command registry hash for provided relations
92
94
  #
93
95
  # @param [RelationRegistry] relations registry
94
- # @param [Hash] repositories
96
+ # @param [Hash] gateways
95
97
  # @param [Array] descendants a list of command subclasses
96
98
  #
97
99
  # @return [Hash]
98
100
  #
99
101
  # @api private
100
- def self.registry(relations, repositories, descendants)
102
+ def self.registry(relations, gateways, descendants)
101
103
  descendants.each_with_object({}) do |klass, h|
102
104
  rel_name = klass.relation
103
105
 
@@ -106,8 +108,8 @@ module ROM
106
108
  relation = relations[rel_name]
107
109
  name = klass.register_as || klass.default_name
108
110
 
109
- repository = repositories[relation.class.repository]
110
- repository.extend_command_class(klass, relation.dataset)
111
+ gateway = gateways[relation.class.gateway]
112
+ gateway.extend_command_class(klass, relation.dataset)
111
113
 
112
114
  (h[rel_name] ||= {})[name] = klass.build(relation)
113
115
  end
@@ -36,7 +36,7 @@ module ROM
36
36
  # @example
37
37
  #
38
38
  # rom.command(:users).try { create(name: 'Jane') }
39
- # rom.command(:users).try { update(:by_id, 1).set(name: 'Jane Doe') }
39
+ # rom.command(:users).try { update(:by_id, 1).call(name: 'Jane Doe') }
40
40
  # rom.command(:users).try { delete(:by_id, 1) }
41
41
  #
42
42
  # @return [Commands::Result]
data/lib/rom/commands.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'rom/support/options'
2
-
3
1
  require 'rom/commands/create'
4
2
  require 'rom/commands/update'
5
3
  require 'rom/commands/delete'
@@ -1,4 +1,8 @@
1
+ require 'rom/support/deprecations'
2
+
1
3
  require 'rom/commands/composite'
4
+ require 'rom/commands/graph'
5
+ require 'rom/commands/lazy'
2
6
 
3
7
  module ROM
4
8
  module Commands
@@ -15,20 +19,26 @@ module ROM
15
19
  # @private
16
20
  class Abstract
17
21
  include Options
22
+ extend Deprecations
18
23
 
19
24
  option :type, allow: [:create, :update, :delete]
25
+ option :source, reader: true
20
26
  option :result, reader: true, allow: [:one, :many]
21
- option :target
22
27
  option :validator, reader: true
23
28
  option :input, reader: true
24
29
  option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
25
30
 
31
+ # @attr_reader [Relation] relation The command's relation
26
32
  attr_reader :relation
27
33
 
34
+ deprecate :target, :relation,
35
+ 'Source relation is now available as `Command#source`'
36
+
28
37
  # @api private
29
38
  def initialize(relation, options = {})
30
- @relation = relation
31
39
  super
40
+ @relation = relation
41
+ @source = options[:source] || relation
32
42
  end
33
43
 
34
44
  # Execute the command
@@ -51,7 +61,7 @@ module ROM
51
61
  def call(*args)
52
62
  tuples = execute(*(curry_args + args))
53
63
 
54
- if result == :one
64
+ if one?
55
65
  tuples.first
56
66
  else
57
67
  tuples
@@ -67,7 +77,11 @@ module ROM
67
77
  #
68
78
  # @api public
69
79
  def curry(*args)
70
- self.class.new(relation, options.merge(curry_args: args))
80
+ if curry_args.empty? && args.first.is_a?(Proc)
81
+ Lazy.new(self, args.first)
82
+ else
83
+ self.class.build(relation, options.merge(curry_args: args))
84
+ end
71
85
  end
72
86
  alias_method :with, :curry
73
87
 
@@ -89,48 +103,53 @@ module ROM
89
103
  Composite.new(self, other)
90
104
  end
91
105
 
92
- # Return new update command with new relation
93
- #
106
+ # @api public
107
+ def combine(*others)
108
+ Graph.new(self, others)
109
+ end
110
+
94
111
  # @api private
95
- def new(*args, &block)
96
- self.class.build(relation.public_send(*args, &block), options)
112
+ def lazy?
113
+ false
97
114
  end
98
115
 
99
- # Target relation on which the command will operate
100
- #
101
- # By default this is set to the relation that's passed to the constructor.
102
- # Specialized commands like Delete may set the target to a different
103
- # relation.
104
- #
105
- # @return [Relation]
106
- #
107
- # @api public
108
- def target
109
- relation
116
+ # @api private
117
+ def graph?
118
+ false
119
+ end
120
+
121
+ # @api private
122
+ def one?
123
+ result.equal?(:one)
124
+ end
125
+
126
+ # @api private
127
+ def many?
128
+ result.equal?(:many)
110
129
  end
111
130
 
112
- # Assert that tuple count in the target relation corresponds to :result
131
+ # Assert that tuple count in the relation corresponds to :result
113
132
  # setting
114
133
  #
115
134
  # @raise TupleCountMismatchError
116
135
  #
117
136
  # @api private
118
137
  def assert_tuple_count
119
- if result == :one && tuple_count > 1
138
+ if one? && tuple_count > 1
120
139
  raise TupleCountMismatchError, "#{inspect} expects one tuple"
121
140
  end
122
141
  end
123
142
 
124
- # Return number of tuples in the target relation
143
+ # Return number of tuples in the relation relation
125
144
  #
126
- # This should be overridden by repositories when `#count` is not available
145
+ # This should be overridden by gateways when `#count` is not available
127
146
  # in the relation objects
128
147
  #
129
148
  # @return [Fixnum]
130
149
  #
131
150
  # @api private
132
151
  def tuple_count
133
- target.count
152
+ relation.count
134
153
  end
135
154
 
136
155
  # @api private
@@ -138,12 +157,23 @@ module ROM
138
157
  relation.respond_to?(name) || super
139
158
  end
140
159
 
160
+ # @api private
161
+ def new(new_relation)
162
+ self.class.build(new_relation, options.merge(source: relation))
163
+ end
164
+
141
165
  private
142
166
 
143
167
  # @api private
144
168
  def method_missing(name, *args, &block)
145
169
  if relation.respond_to?(name)
146
- new(name, *args, &block)
170
+ response = relation.public_send(name, *args, &block)
171
+
172
+ if response.instance_of?(relation.class)
173
+ new(response)
174
+ else
175
+ response
176
+ end
147
177
  else
148
178
  super
149
179
  end
@@ -14,22 +14,34 @@ module ROM
14
14
  def call(*args)
15
15
  response = left.call(*args)
16
16
 
17
- if result == :one
17
+ if one? && !graph?
18
18
  if right.is_a?(Command) || right.is_a?(Commands::Composite)
19
19
  right.call([response].first)
20
20
  else
21
21
  right.call([response]).first
22
22
  end
23
+ elsif one? && graph?
24
+ right.call(response).first
23
25
  else
24
26
  right.call(response)
25
27
  end
26
28
  end
27
29
  alias_method :[], :call
28
30
 
31
+ # @api private
32
+ def graph?
33
+ left.is_a?(Graph)
34
+ end
35
+
29
36
  # @api private
30
37
  def result
31
38
  left.result
32
39
  end
40
+
41
+ # @api private
42
+ def decorate?(response)
43
+ super || response.is_a?(Graph)
44
+ end
33
45
  end
34
46
  end
35
47
  end
@@ -8,14 +8,6 @@ module ROM
8
8
  #
9
9
  # @abstract
10
10
  class Delete < Command
11
- attr_reader :target
12
-
13
- # @api private
14
- def initialize(relation, options = {})
15
- super
16
- @target = options[:target] || relation
17
- end
18
-
19
11
  # @see AbstractCommand#call
20
12
  def call(*args)
21
13
  assert_tuple_count
@@ -0,0 +1,102 @@
1
+ require 'rom/pipeline'
2
+ require 'rom/support/options'
3
+ require 'rom/commands/graph/class_interface'
4
+
5
+ module ROM
6
+ module Commands
7
+ # Command graph
8
+ #
9
+ # @api private
10
+ class Graph
11
+ extend ClassInterface
12
+
13
+ include Options
14
+ include Pipeline
15
+ include Pipeline::Proxy
16
+
17
+ # @attr_reader [Command] root The root command
18
+ attr_reader :root
19
+
20
+ # @attr_reader [Array<Command>] nodes The child commands
21
+ attr_reader :nodes
22
+
23
+ alias_method :left, :root
24
+ alias_method :right, :nodes
25
+
26
+ option :mappers, reader: true, default: proc { MapperRegistry.new }
27
+
28
+ # @api private
29
+ def initialize(root, nodes, options = {})
30
+ super
31
+ @root = root
32
+ @nodes = nodes
33
+ end
34
+
35
+ # Calls root and all nodes with the result from root
36
+ #
37
+ # Graph results are mappable through `combine` operation in mapper DSL
38
+ #
39
+ # @example
40
+ # create_user = rom.command(:users).create
41
+ # create_task = rom.command(:tasks).create
42
+ #
43
+ # command = create_user
44
+ # .with(name: 'Jane')
45
+ # .combine(create_task.with(title: 'Task'))
46
+ #
47
+ # command.call
48
+ #
49
+ # @return [Array] nested array with command results
50
+ #
51
+ # @api public
52
+ def call(*args)
53
+ begin
54
+ left = root.call(*args)
55
+
56
+ right = nodes.map do |node|
57
+ begin
58
+ response =
59
+ if node.lazy?
60
+ node.call(args.first, left)
61
+ else
62
+ node.call(left)
63
+ end
64
+ rescue => err
65
+ raise CommandFailure.new(node, err)
66
+ rescue CommandFailure => err
67
+ raise err
68
+ end
69
+
70
+ if node.one? && !node.graph?
71
+ [response]
72
+ else
73
+ response
74
+ end
75
+ end
76
+
77
+ if one?
78
+ [[left], right]
79
+ else
80
+ [left, right]
81
+ end
82
+ rescue => err
83
+ raise CommandFailure.new(root, err)
84
+ rescue CommandFailure => err
85
+ raise err
86
+ end
87
+ end
88
+
89
+ # Return a new graph with updated options
90
+ #
91
+ # @api private
92
+ def with(new_options)
93
+ self.class.new(root, nodes, options.merge(new_options))
94
+ end
95
+
96
+ # @api private
97
+ def graph?
98
+ true
99
+ end
100
+ end
101
+ end
102
+ end