rom 1.0.0 → 2.0.0

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.travis.yml +5 -3
  4. data/CHANGELOG.md +38 -0
  5. data/Gemfile +2 -14
  6. data/README.md +11 -17
  7. data/lib/rom.rb +2 -0
  8. data/lib/rom/association_set.rb +26 -0
  9. data/lib/rom/command.rb +50 -45
  10. data/lib/rom/command_registry.rb +26 -3
  11. data/lib/rom/commands/class_interface.rb +52 -19
  12. data/lib/rom/commands/composite.rb +5 -0
  13. data/lib/rom/commands/delete.rb +1 -5
  14. data/lib/rom/commands/graph.rb +11 -0
  15. data/lib/rom/commands/lazy.rb +2 -0
  16. data/lib/rom/commands/update.rb +1 -5
  17. data/lib/rom/configuration.rb +2 -0
  18. data/lib/rom/container.rb +3 -3
  19. data/lib/rom/global.rb +1 -23
  20. data/lib/rom/memory/commands.rb +2 -0
  21. data/lib/rom/memory/relation.rb +3 -0
  22. data/lib/rom/memory/storage.rb +4 -7
  23. data/lib/rom/memory/types.rb +9 -0
  24. data/lib/rom/pipeline.rb +26 -12
  25. data/lib/rom/plugin_registry.rb +2 -2
  26. data/lib/rom/plugins/command/schema.rb +26 -0
  27. data/lib/rom/plugins/configuration/configuration_dsl.rb +2 -1
  28. data/lib/rom/plugins/relation/key_inference.rb +18 -3
  29. data/lib/rom/plugins/relation/registry_reader.rb +3 -1
  30. data/lib/rom/plugins/relation/view.rb +11 -6
  31. data/lib/rom/relation.rb +76 -16
  32. data/lib/rom/relation/class_interface.rb +44 -3
  33. data/lib/rom/relation/curried.rb +13 -4
  34. data/lib/rom/relation/graph.rb +15 -5
  35. data/lib/rom/relation/loaded.rb +42 -6
  36. data/lib/rom/relation/name.rb +102 -0
  37. data/lib/rom/relation_registry.rb +5 -0
  38. data/lib/rom/schema.rb +87 -0
  39. data/lib/rom/schema/dsl.rb +58 -0
  40. data/lib/rom/setup/auto_registration.rb +2 -2
  41. data/lib/rom/setup/finalize.rb +5 -5
  42. data/lib/rom/setup/finalize/{commands.rb → finalize_commands.rb} +2 -22
  43. data/lib/rom/setup/finalize/{mappers.rb → finalize_mappers.rb} +0 -0
  44. data/lib/rom/setup/finalize/finalize_relations.rb +60 -0
  45. data/lib/rom/types.rb +18 -0
  46. data/lib/rom/version.rb +1 -1
  47. data/log/.gitkeep +0 -0
  48. data/rom.gemspec +4 -2
  49. data/spec/integration/command_registry_spec.rb +13 -0
  50. data/spec/integration/commands/delete_spec.rb +0 -17
  51. data/spec/integration/commands/graph_builder_spec.rb +1 -1
  52. data/spec/integration/commands/graph_spec.rb +1 -1
  53. data/spec/integration/commands/update_spec.rb +0 -19
  54. data/spec/integration/commands_spec.rb +10 -3
  55. data/spec/integration/multi_repo_spec.rb +1 -1
  56. data/spec/integration/relations/default_dataset_spec.rb +27 -4
  57. data/spec/integration/setup_spec.rb +1 -4
  58. data/spec/shared/command_behavior.rb +17 -7
  59. data/spec/shared/container.rb +2 -2
  60. data/spec/shared/gateway_only.rb +1 -1
  61. data/spec/spec_helper.rb +5 -6
  62. data/spec/unit/rom/association_set_spec.rb +23 -0
  63. data/spec/unit/rom/auto_registration_spec.rb +1 -1
  64. data/spec/unit/rom/commands/lazy_spec.rb +8 -0
  65. data/spec/unit/rom/commands_spec.rb +45 -7
  66. data/spec/unit/rom/configurable_spec.rb +1 -1
  67. data/spec/unit/rom/container_spec.rb +6 -0
  68. data/spec/unit/rom/create_container_spec.rb +1 -1
  69. data/spec/unit/rom/environment_spec.rb +1 -1
  70. data/spec/unit/rom/memory/commands_spec.rb +43 -0
  71. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +70 -12
  72. data/spec/unit/rom/plugins/relation/view_spec.rb +4 -0
  73. data/spec/unit/rom/relation/graph_spec.rb +10 -0
  74. data/spec/unit/rom/relation/lazy_spec.rb +3 -3
  75. data/spec/unit/rom/relation/loaded_spec.rb +15 -0
  76. data/spec/unit/rom/relation/name_spec.rb +51 -0
  77. data/spec/unit/rom/relation/schema_spec.rb +117 -0
  78. data/spec/unit/rom/relation_spec.rb +37 -7
  79. data/spec/unit/rom/schema_spec.rb +10 -0
  80. metadata +51 -12
  81. data/lib/rom/setup/finalize/relations.rb +0 -53
  82. data/spec/unit/rom/global_spec.rb +0 -18
  83. data/spec/unit/rom/registry_spec.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25732b8177fd64f45b5e98ee76444dfd87fcbd87
4
- data.tar.gz: 1bb6afd01547c8c4455c0ba1f56ea3b939b45ea4
3
+ metadata.gz: a49d8efc969391ec0d48db3e9f41d29299537e44
4
+ data.tar.gz: 5c4ba339c27f15887468a364bd89de0c7c722572
5
5
  SHA512:
6
- metadata.gz: 51358af05cf918b0b8271758e7a56a01830bfd5c1252819f949cc4e8eeabde918568f5980faba63038cf2239b0fa0df83ac40ac69a902402fd4325a45144a36b
7
- data.tar.gz: bccc3cea146a146045b76d8c949d8fb8983302379bcff680c00e357b24793d2ae897361a3f6570a9a129b776a49d6a6c75046e45001a81d92f914246d4076ddf
6
+ metadata.gz: b720586dcc0542d8ab45d22209d91898c695a8f509af73f3bb1f967f3952f39f83ed3c9bcb7aa7b4ec87087518e7f9f2f592c4d5a4ad5763a5a3c8f9829389de
7
+ data.tar.gz: 1b5f6a9ae2038ea0b539d4e6931a1be194aa13d2cc2b7fbc3a1af03455bc028956f96a4ba39ab4cf94fd551931b86ab425e2c61bef8b13e2c823cd3a0f4ff967
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
1
  --color
2
2
  --order random
3
- --warnings
3
+ --require ./spec/spec_helper.rb
@@ -9,11 +9,10 @@ rvm:
9
9
  - 2.0
10
10
  - 2.1
11
11
  - 2.2
12
- - 2.3.0
12
+ - 2.3.1
13
13
  - rbx-2
14
- - jruby-9000
14
+ - jruby-9.0.5.0
15
15
  - ruby-head
16
- - jruby-head
17
16
  env:
18
17
  global:
19
18
  - JRUBY_OPTS='--dev -J-Xmx1024M'
@@ -21,6 +20,9 @@ matrix:
21
20
  allow_failures:
22
21
  - rvm: ruby-head
23
22
  - rvm: jruby-head
23
+ include:
24
+ - rvm: jruby-head
25
+ before_install: gem install bundler --no-ri --no-rdoc
24
26
  notifications:
25
27
  webhooks:
26
28
  urls:
@@ -1,3 +1,41 @@
1
+ ## v2.0.0 2016-07-27
2
+
3
+ ### Added
4
+
5
+ - Extendible `schema` DSL for relations with attribute and type definitions (solnic)
6
+ - New command plugin `:schema` which will set up an input handler from schema definition (solnic)
7
+ - New command option `restrictible` for commands that can use a restricted relation (solnic)
8
+ - More meaningful exception is raised when trying to access a non-existant command (thiagoa)
9
+ - `Relation::Name` class that contains both relation and dataset names (flash-gordon)
10
+ - `Relation::Loaded#pluck` returning values under specified key (solnic)
11
+ - `Relation::Loaded#primary_keys` returning a list of primary keys from a materialized relation (solnic)
12
+
13
+ #### New low-level APIs
14
+
15
+ - `Command.create_class` for building a command class dynamically (solnic)
16
+ - `Command.extend_for_relation` for extending a command with relation view interface (solnic)
17
+
18
+ ### Fixed
19
+
20
+ - [BREAKING] command graphs return materialized results (a hash or an array) (solnic)
21
+ - `Container#disconnect` properly delegates to gateways (endash)
22
+ - `Relation#with` properly carries original options (solnic)
23
+ - Command pipeline will stop processing if result was `nil` or an empty array (solnic)
24
+
25
+ ### Changed
26
+
27
+ - [BREAKING] `ROM.env` **is gone** (solnic)
28
+ - [BREAKING] `Update` and `Delete` no longer calls `assert_tuple_count` [more info](https://github.com/rom-rb/rom/commit/bec2c4c1dce370670c90f529feb1b4db0e6e4bd9) (solnic)
29
+ - [BREAKING] `Relation#name` and `Command#name` now returns `Relation::Name` instance (flash-gordon)
30
+ - `Command.validator` is now deprecated [more info](https://github.com/rom-rb/rom/commit/80bb8411bd411f05d9c51106ae026ad412a2f25f) (solnic)
31
+ - `Relation.dataset` yields a relation class when block was passed (solnic)
32
+ - `Relation#attributes` can return attributes explicitly passed via options (solnic)
33
+ - Relation `:key_inference` plugin supports schema information from other relations (solnic)
34
+ - `auto_registration` coerces its directory to a pathname now (adz)
35
+ - `macros` are now enabled by default in in-line setup block (endash)
36
+
37
+ [Compare v1.0.0...v2.0.0](https://github.com/rom-rb/rom/compare/v1.0.0...v2.0.0)
38
+
1
39
  ## v1.0.0 2016-01-06
2
40
 
3
41
  ### Added
data/Gemfile CHANGED
@@ -11,8 +11,6 @@ group :test do
11
11
  gem 'virtus'
12
12
  gem 'anima', '~> 0.2.0'
13
13
  gem 'minitest'
14
- gem 'thread_safe'
15
- gem 'activesupport'
16
14
  gem 'inflecto', '~> 0.0', '>= 0.0.2'
17
15
 
18
16
  platforms :rbx do
@@ -29,21 +27,11 @@ group :sql do
29
27
  end
30
28
 
31
29
  group :benchmarks do
32
- gem 'activerecord', '4.2.0'
30
+ gem 'activerecord', '5.0.0.beta4'
33
31
  gem 'benchmark-ips', '~> 2.2.0'
32
+ gem 'rom-repository', github: 'rom-rb/rom-repository', branch: 'master'
34
33
  end
35
34
 
36
35
  group :tools do
37
- gem 'rubocop', '~> 0.31'
38
-
39
- gem 'guard'
40
- gem 'guard-rspec'
41
- gem 'guard-rubocop'
42
-
43
36
  gem 'byebug', platform: :mri
44
-
45
- platform :mri do
46
- gem 'mutant'
47
- gem 'mutant-rspec'
48
- end
49
37
  end
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [coveralls]: https://coveralls.io/r/rom-rb/rom
6
6
  [inchpages]: http://inch-ci.org/github/rom-rb/rom/
7
7
 
8
- # Ruby Object Mapper [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)](https://gitter.im/rom-rb/chat) [![Stories in Ready](https://badge.waffle.io/rom-rb/rom.png?label=ready&title=Ready)](https://waffle.io/rom-rb/rom)
8
+ # rom [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)](https://gitter.im/rom-rb/chat)
9
9
 
10
10
  [![Gem Version](https://badge.fury.io/rb/rom.svg)][gem]
11
11
  [![Build Status](https://travis-ci.org/rom-rb/rom.svg?branch=master)][travis]
@@ -15,14 +15,13 @@
15
15
  [![Inline docs](http://inch-ci.org/github/rom-rb/rom.svg?branch=master&style=flat)][inchpages]
16
16
 
17
17
  Ruby Object Mapper (ROM) is a data mapping and persistence toolkit for Ruby
18
- with the goal to provide powerful object mapping capabilities without limiting the
19
- full power of your datastore.
18
+ with the goal to provide powerful object mapping capabilities without limiting
19
+ the full power of your datastore.
20
20
 
21
21
  Learn more:
22
22
 
23
- * [Introduction](http://rom-rb.org/introduction/)
24
- * [Guides](http://rom-rb.org/guides/)
25
- * [Tutorials](http://rom-rb.org/tutorials/)
23
+ * [Introduction](http://rom-rb.org/learn/introduction)
24
+ * [Quick Start](http://rom-rb.org/learn/repositories/quick-start)
26
25
 
27
26
  ## Support Campaign
28
27
 
@@ -33,43 +32,38 @@ You can support ROM's development via our [campaign on Bountysource](https://sal
33
32
  There are other gems within the rom ecosystem that you will find useful:
34
33
 
35
34
  * [rom-repository](https://github.com/rom-rb/rom-repository) a higher-level, convenient abstraction with auto-mapping
36
- * [rom-model](https://github.com/rom-rb/rom-model) extensions for coercion and validation
35
+ * (WIP) [rom-migrator](https://github.com/rom-rb/rom-migrator) common APIs for database migrations
37
36
 
38
37
  ## Adapters
39
38
 
39
+ * [rom-sql](https://github.com/rom-rb/rom-sql) (supported URI schemes: ado amalgalite cubrid db2 dbi do fdbsql firebird ibmdb informix jdbc mysql mysql2 odbc openbase oracle postgres sqlanywhere sqlite swift tinytds)
40
+ * [rom-yesql](https://github.com/rom-rb/rom-yesql)
41
+ * [rom-http](https://github.com/rom-rb/rom-http)
40
42
  * [rom-couchdb](https://github.com/rom-rb/rom-couchdb)
41
43
  * [rom-csv](https://github.com/rom-rb/rom-csv)
44
+ * [rom-yaml](https://github.com/rom-rb/rom-yaml)
42
45
  * [rom-cassandra](https://github.com/rom-rb/rom-cassandra)
43
46
  * [rom-event_store](https://github.com/rom-rb/rom-event_store)
44
47
  * [rom-git](https://github.com/rom-rb/rom-git)
45
- * [rom-http](https://github.com/rom-rb/rom-http)
46
48
  * [rom-influxdb](https://github.com/rom-rb/rom-influxdb)
47
49
  * [rom-json](https://github.com/rom-rb/rom-json)
48
50
  * [rom-kafka](https://github.com/rom-rb/rom-kafka)
49
51
  * [rom-mongo](https://github.com/rom-rb/rom-mongo)
50
52
  * [rom-neo4j](https://github.com/rom-rb/rom-neo4j)
51
53
  * [rom-rethinkdb](https://github.com/rom-rb/rom-rethinkdb)
52
- * [rom-sql](https://github.com/rom-rb/rom-sql)
53
- * [rom-yaml](https://github.com/rom-rb/rom-yaml)
54
- * [rom-yesql](https://github.com/rom-rb/rom-yesql)
55
54
 
56
55
  See [issues](https://github.com/rom-rb/rom/issues?q=is%3Aopen+is%3Aissue+label%3Aadapter+label%3Afeature)
57
56
  for a list of adapters that are planned to be added soon.
58
57
 
59
58
  ## Framework integrations
60
59
 
61
- * [rom-lotus](https://github.com/rom-rb/rom-lotus)
62
60
  * [rom-rails](https://github.com/rom-rb/rom-rails)
63
61
  * [rom-roda](https://github.com/rom-rb/rom-roda)
64
62
 
65
- ## ROADMAP
66
-
67
- ROM is on its way towards 1.0.0. You can see an overview of tasks scheduled for 1.0.0 on our [waffle board](https://waffle.io/rom-rb/rom?label=1.0.0). Please notice that most of the 1.0.0 features/changes will become part of minor (0.x) upgrades before 1.0.0 final gets released.
68
-
69
63
  ## Community
70
64
 
71
65
  * [Official Blog](http://rom-rb.org/blog/)
72
- * [Discussion Forum](http://discourse.rom-rb.org)
66
+ * [Discussion Forum](http://discuss.rom-rb.org)
73
67
  * [Gitter Channel](https://gitter.im/rom-rb/chat)
74
68
 
75
69
  ## Credits
data/lib/rom.rb CHANGED
@@ -34,6 +34,7 @@ require 'rom/create_container'
34
34
  # register core plugins
35
35
  require 'rom/plugins/configuration/configuration_dsl'
36
36
  require 'rom/plugins/relation/registry_reader'
37
+ require 'rom/plugins/command/schema'
37
38
 
38
39
  module ROM
39
40
  extend Global
@@ -41,5 +42,6 @@ module ROM
41
42
  plugins do
42
43
  register :macros, ROM::ConfigurationPlugins::ConfigurationDSL, type: :configuration
43
44
  register :registry_reader, ROM::Plugins::Relation::RegistryReader, type: :relation
45
+ register :schema, ROM::Plugins::Command::Schema, type: :command
44
46
  end
45
47
  end
@@ -0,0 +1,26 @@
1
+ require 'rom/support/registry'
2
+ require 'rom/support/inflector'
3
+
4
+ module ROM
5
+ class AssociationSet < ROM::Registry
6
+ # @api private
7
+ def try(name, &block)
8
+ if key?(name)
9
+ yield(self[name])
10
+ else
11
+ false
12
+ end
13
+ end
14
+
15
+ # @api private
16
+ def [](name)
17
+ key = name.to_sym
18
+
19
+ if key?(key)
20
+ super
21
+ else
22
+ super(Inflector.singularize(key))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,4 +1,6 @@
1
+ require 'rom/support/deprecations'
1
2
  require 'rom/support/options'
3
+ require 'rom/pipeline'
2
4
 
3
5
  require 'rom/commands/class_interface'
4
6
  require 'rom/commands/composite'
@@ -18,15 +20,18 @@ module ROM
18
20
  #
19
21
  # @private
20
22
  class Command
23
+ DEFAULT_VALIDATOR = proc {}
24
+
25
+ include Dry::Equalizer(:relation, :options)
21
26
  include Commands
27
+ include Pipeline::Operator
22
28
 
23
29
  extend ClassMacros
24
30
  extend ClassInterface
25
31
 
26
32
  include Options
27
- include Dry::Equalizer(:relation, :options)
28
33
 
29
- defines :adapter, :relation, :result, :input, :validator, :register_as
34
+ defines :adapter, :relation, :result, :input, :validator, :register_as, :restrictable
30
35
 
31
36
  option :type, allow: [:create, :update, :delete]
32
37
  option :source, reader: true
@@ -36,9 +41,26 @@ module ROM
36
41
  option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
37
42
 
38
43
  input Hash
39
- validator proc {}
44
+ validator DEFAULT_VALIDATOR
40
45
  result :many
41
46
 
47
+ # @deprecated
48
+ #
49
+ # @api public
50
+ def self.validator(vp = nil)
51
+ if defined?(@validator) && vp.nil?
52
+ @validator
53
+ else
54
+ unless vp.equal?(DEFAULT_VALIDATOR)
55
+ Deprecations.announce(
56
+ "#{name}.validator",
57
+ 'Please handle validation before calling commands'
58
+ )
59
+ end
60
+ super
61
+ end
62
+ end
63
+
42
64
  # @attr_reader [Relation] relation The command's relation
43
65
  attr_reader :relation
44
66
 
@@ -49,6 +71,24 @@ module ROM
49
71
  @source = options[:source] || relation
50
72
  end
51
73
 
74
+ # Return name of this command's relation
75
+ #
76
+ # @return [ROM::Relation::Name]
77
+ #
78
+ # @api public
79
+ def name
80
+ relation.name
81
+ end
82
+
83
+ # Return gateway of this command's relation
84
+ #
85
+ # @return [Symbol]
86
+ #
87
+ # @api public
88
+ def gateway
89
+ relation.gateway
90
+ end
91
+
52
92
  # Execute the command
53
93
  #
54
94
  # @abstract
@@ -66,8 +106,8 @@ module ROM
66
106
  # Call the command and return one or many tuples
67
107
  #
68
108
  # @api public
69
- def call(*args)
70
- tuples = execute(*(curry_args + args))
109
+ def call(*args, &block)
110
+ tuples = execute(*(curry_args + args), &block)
71
111
 
72
112
  if one?
73
113
  tuples.first
@@ -93,24 +133,6 @@ module ROM
93
133
  end
94
134
  alias_method :with, :curry
95
135
 
96
- # Compose a command with another one
97
- #
98
- # The other one will be called with the result from the first one
99
- #
100
- # @example
101
- #
102
- # command = users.create.curry(name: 'Jane')
103
- # command >>= tasks.create.curry(title: 'Task One')
104
- #
105
- # command.call # creates user, passes it to tasks and creates task
106
- #
107
- # @return [Composite]
108
- #
109
- # @api public
110
- def >>(other)
111
- Composite.new(self, other)
112
- end
113
-
114
136
  # @api public
115
137
  def combine(*others)
116
138
  Graph.new(self, others)
@@ -136,33 +158,16 @@ module ROM
136
158
  result.equal?(:many)
137
159
  end
138
160
 
139
- # Assert that tuple count in the relation corresponds to :result
140
- # setting
141
- #
142
- # @raise TupleCountMismatchError
143
- #
144
161
  # @api private
145
- def assert_tuple_count
146
- if one? && tuple_count > 1
147
- raise TupleCountMismatchError, "#{inspect} expects one tuple"
148
- end
162
+ def new(new_relation)
163
+ self.class.build(new_relation, options.merge(source: relation))
149
164
  end
150
165
 
151
- # Return number of tuples in the relation relation
152
- #
153
- # This should be overridden by gateways when `#count` is not available
154
- # in the relation objects
155
- #
156
- # @return [Fixnum]
157
- #
158
- # @api private
159
- def tuple_count
160
- relation.count
161
- end
166
+ private
162
167
 
163
168
  # @api private
164
- def new(new_relation)
165
- self.class.build(new_relation, options.merge(source: relation))
169
+ def composite_class
170
+ Command::Composite
166
171
  end
167
172
  end
168
173
  end
@@ -8,6 +8,15 @@ module ROM
8
8
  include Commands
9
9
  include Options
10
10
 
11
+ CommandNotFoundError = Class.new(KeyError)
12
+
13
+ # Name of the relation from which commands are under
14
+ #
15
+ # @return [String]
16
+ #
17
+ # @api private
18
+ attr_reader :relation_name
19
+
11
20
  # Internal command registry
12
21
  #
13
22
  # @return [Registry]
@@ -19,8 +28,10 @@ module ROM
19
28
  option :mapper, reader: true
20
29
 
21
30
  # @api private
22
- def initialize(elements, options = EMPTY_HASH)
31
+ def initialize(relation_name, elements, options = EMPTY_HASH)
23
32
  super
33
+
34
+ @relation_name = relation_name
24
35
  @registry =
25
36
  if elements.is_a?(Registry)
26
37
  elements
@@ -73,7 +84,7 @@ module ROM
73
84
  #
74
85
  # @api public
75
86
  def [](name)
76
- command = registry[name]
87
+ command = fetch_command(name)
77
88
  mapper = options[:mapper]
78
89
 
79
90
  if mapper
@@ -104,11 +115,23 @@ module ROM
104
115
  #
105
116
  # @api private
106
117
  def with(new_options)
107
- self.class.new(registry, options.merge(new_options))
118
+ self.class.new(relation_name, registry, options.merge(new_options))
108
119
  end
109
120
 
110
121
  private
111
122
 
123
+ # Fetch a command from the registry and raise a specialized error
124
+ # in case the command is not found
125
+ #
126
+ # @api private
127
+ def fetch_command(name)
128
+ registry.fetch(name) do
129
+ raise CommandNotFoundError.new(
130
+ "There is no :#{name} command for :#{relation_name} relation"
131
+ )
132
+ end
133
+ end
134
+
112
135
  # Allow checking if a certain command is available using dot-notation
113
136
  #
114
137
  # @api private