dry-system 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +39 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +34 -0
  5. data/.rubocop_todo.yml +26 -0
  6. data/.travis.yml +26 -0
  7. data/.yardopts +5 -0
  8. data/CHANGELOG.md +158 -0
  9. data/Gemfile +9 -0
  10. data/LICENSE +20 -0
  11. data/README.md +23 -0
  12. data/Rakefile +12 -0
  13. data/dry-system.gemspec +30 -0
  14. data/examples/standalone/Gemfile +5 -0
  15. data/examples/standalone/lib/user_repo.rb +5 -0
  16. data/examples/standalone/run.rb +7 -0
  17. data/examples/standalone/system/boot/persistence.rb +13 -0
  18. data/examples/standalone/system/container.rb +9 -0
  19. data/examples/standalone/system/import.rb +3 -0
  20. data/lib/dry-system.rb +1 -0
  21. data/lib/dry/system.rb +4 -0
  22. data/lib/dry/system/auto_registrar.rb +80 -0
  23. data/lib/dry/system/booter.rb +101 -0
  24. data/lib/dry/system/component.rb +167 -0
  25. data/lib/dry/system/constants.rb +9 -0
  26. data/lib/dry/system/container.rb +500 -0
  27. data/lib/dry/system/errors.rb +62 -0
  28. data/lib/dry/system/importer.rb +53 -0
  29. data/lib/dry/system/injector.rb +68 -0
  30. data/lib/dry/system/lifecycle.rb +104 -0
  31. data/lib/dry/system/loader.rb +69 -0
  32. data/lib/dry/system/version.rb +5 -0
  33. data/spec/fixtures/components/bar.rb +5 -0
  34. data/spec/fixtures/components/bar/baz.rb +4 -0
  35. data/spec/fixtures/components/foo.rb +2 -0
  36. data/spec/fixtures/import_test/config/application.yml +2 -0
  37. data/spec/fixtures/import_test/lib/test/bar.rb +4 -0
  38. data/spec/fixtures/import_test/lib/test/foo.rb +5 -0
  39. data/spec/fixtures/import_test/system/boot/bar.rb +11 -0
  40. data/spec/fixtures/lazytest/config/application.yml +2 -0
  41. data/spec/fixtures/lazytest/lib/test/dep.rb +4 -0
  42. data/spec/fixtures/lazytest/lib/test/foo.rb +5 -0
  43. data/spec/fixtures/lazytest/lib/test/models.rb +4 -0
  44. data/spec/fixtures/lazytest/lib/test/models/book.rb +6 -0
  45. data/spec/fixtures/lazytest/lib/test/models/user.rb +6 -0
  46. data/spec/fixtures/lazytest/system/boot/bar.rb +15 -0
  47. data/spec/fixtures/namespaced_components/namespaced/bar.rb +5 -0
  48. data/spec/fixtures/namespaced_components/namespaced/foo.rb +4 -0
  49. data/spec/fixtures/other/config/boot/bar.rb +11 -0
  50. data/spec/fixtures/other/lib/test/dep.rb +4 -0
  51. data/spec/fixtures/other/lib/test/foo.rb +5 -0
  52. data/spec/fixtures/other/lib/test/models.rb +4 -0
  53. data/spec/fixtures/other/lib/test/models/book.rb +6 -0
  54. data/spec/fixtures/other/lib/test/models/user.rb +6 -0
  55. data/spec/fixtures/test/config/application.yml +2 -0
  56. data/spec/fixtures/test/config/subapp.yml +2 -0
  57. data/spec/fixtures/test/lib/test/dep.rb +4 -0
  58. data/spec/fixtures/test/lib/test/foo.rb +5 -0
  59. data/spec/fixtures/test/lib/test/models.rb +4 -0
  60. data/spec/fixtures/test/lib/test/models/book.rb +6 -0
  61. data/spec/fixtures/test/lib/test/models/user.rb +6 -0
  62. data/spec/fixtures/test/lib/test/singleton_dep.rb +7 -0
  63. data/spec/fixtures/test/log/.gitkeep +0 -0
  64. data/spec/fixtures/test/system/boot/bar.rb +11 -0
  65. data/spec/fixtures/test/system/boot/client.rb +7 -0
  66. data/spec/fixtures/test/system/boot/db.rb +1 -0
  67. data/spec/fixtures/test/system/boot/logger.rb +5 -0
  68. data/spec/fixtures/umbrella/system/boot/db.rb +10 -0
  69. data/spec/integration/boot_spec.rb +18 -0
  70. data/spec/integration/import_spec.rb +63 -0
  71. data/spec/spec_helper.rb +47 -0
  72. data/spec/unit/component_spec.rb +116 -0
  73. data/spec/unit/container/auto_register_spec.rb +85 -0
  74. data/spec/unit/container/finalize_spec.rb +85 -0
  75. data/spec/unit/container/import_spec.rb +70 -0
  76. data/spec/unit/container/injector_spec.rb +29 -0
  77. data/spec/unit/container_spec.rb +165 -0
  78. data/spec/unit/injector_spec.rb +72 -0
  79. data/spec/unit/loader_spec.rb +64 -0
  80. metadata +295 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c398714a52ae6d9417f4540e7895ac9c6fdf0ec
4
+ data.tar.gz: 598cf31307d04a3e544cfaa86d6a4859801a35b2
5
+ SHA512:
6
+ metadata.gz: 492196a3389265c2b78b14237290ae00088f930c1e6d3943def48ebf45d5c2b20e574d00172bd4db8cf15e55e5772006959976b850ffc6a81dac0d739246a79d
7
+ data.tar.gz: d76f194b875767219586d35c72a2fe910f1c8d2603ce5d527b2686906aaa824e783b04ca344aa659b0be85d4f8ae63b524e0c10996f63d83b9ada8ff4b347604
@@ -0,0 +1,39 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ # Gemfile.lock
31
+ # .ruby-version
32
+ # .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
36
+ Gemfile.lock
37
+
38
+ ## Specific to RubyMine
39
+ .idea
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require ./spec/spec_helper
3
+ --order random
@@ -0,0 +1,34 @@
1
+ # Generated by `rubocop --auto-gen-config`
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+ # No need to handle LoadError in spec helper
5
+ Lint/HandleExceptions:
6
+ Exclude:
7
+ - spec/spec_helper.rb
8
+
9
+ Style/FileName:
10
+ Exclude:
11
+ - 'lib/dry-component.rb'
12
+
13
+ # Documentation checked by Inch CI
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ # Ain't nobody got time for that!
18
+ Style/MethodCallParentheses:
19
+ Enabled: false
20
+
21
+ Style/Lambda:
22
+ Enabled: false
23
+
24
+ Style/BlockDelimiters:
25
+ Enabled: false
26
+
27
+ Style/LambdaCall:
28
+ EnforcedStyle: braces
29
+
30
+ Style/MultilineBlockChain:
31
+ Enabled: false
32
+
33
+ Style/StabbyLambdaParentheses:
34
+ EnforcedStyle: require_no_parentheses
@@ -0,0 +1,26 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2015-12-23 21:42:26 +0000 using RuboCop version 0.35.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Metrics/AbcSize:
11
+ Max: 25
12
+
13
+ # Offense count: 1
14
+ # Configuration parameters: CountComments.
15
+ Metrics/ClassLength:
16
+ Max: 130
17
+
18
+ # Offense count: 1
19
+ # Configuration parameters: AllowURI, URISchemes.
20
+ Metrics/LineLength:
21
+ Max: 84
22
+
23
+ # Offense count: 2
24
+ # Configuration parameters: CountComments.
25
+ Metrics/MethodLength:
26
+ Max: 14
@@ -0,0 +1,26 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ bundler_args: --without tools
5
+ script:
6
+ - bundle exec rake spec
7
+ rvm:
8
+ - 2.1
9
+ - 2.2
10
+ - 2.3.1
11
+ - rbx
12
+ - jruby-9000
13
+ - ruby-head
14
+ - jruby-head
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
19
+ notifications:
20
+ email: false
21
+ webhooks:
22
+ urls:
23
+ - https://webhooks.gitter.im/e/19098b4253a72c9796db
24
+ on_success: change # options: [always|never|change] default: always
25
+ on_failure: always # options: [always|never|change] default: always
26
+ on_start: false # default: false
@@ -0,0 +1,5 @@
1
+ --no-private
2
+ --hide-void-return
3
+
4
+ --markup-provider=redcarpet
5
+ --markup=markdown
@@ -0,0 +1,158 @@
1
+ # 0.5.0 2016-08-15
2
+
3
+ This is a major refactoring with better internal APIs and improved support
4
+ for multi-container setups. As part of this release `dry-component` has been renamed to `dry-system`.
5
+
6
+ ### Added
7
+
8
+ - Boot DSL with:
9
+ * Lifecycle triggers: `init`, `start` and `stop` (solnic)
10
+ * `use` method which auto-boots a dependency and makes it available in the booting context (solnic)
11
+ - When a component relies on a bootable component, and is being loaded in isolation, the component will be booted automatically (solnic)
12
+
13
+ ### Changed
14
+
15
+ - [BREAKING] `Dry::Component::Container` is now `Dry::System::Container` (solnic)
16
+ - [BREAKING] Configurable `loader` is now a class that accepts container's config and responds to `#constant` and `#instance` (solnic)
17
+ - [BREAKING] `core_dir` renameda to `system_dir` and defaults to `system` (solnic)
18
+ - [BREAKING] `auto_register!` yields `Component` objects (solnic)
19
+
20
+ ### Internal improvements
21
+
22
+ - Use new `Dry::Container#merge` which accepts `:namespace` option (AMHOL)
23
+ - Auto-registration is handled by a `System::AutoRegistrar` object configured in a container (solnic)
24
+ - Booting is now handled by `System::Booter` object configured in a container (solnic)
25
+ - Importing containers is now handled by `System::Importer` object configured in a container (solnic)
26
+
27
+ [Compare v0.4.3...v0.5.0](https://github.com/dry-rb/dry-component/compare/v0.4.3...v0.5.0)
28
+
29
+ # 0.4.3 - 2016-08-01
30
+
31
+ ### Fixed
32
+
33
+ - Return immediately from `Container.load_component` if the requested component key already exists in the container. This fixes a crash when requesting to load a manually registered component with a name that doesn't map to a filename (timriley in [#24](https://github.com/dry-rb/dry-component/pull/24))
34
+
35
+ [Compare v0.4.2...v0.4.3](https://github.com/dry-rb/dry-component/compare/v0.4.2...v0.4.3)
36
+
37
+ # 0.4.2 - 2016-07-26
38
+
39
+ ### Fixed
40
+
41
+ - Ensure file components can be loaded when they're requested for the first time using their shorthand container identifier (i.e. with the container's default namespace removed) (timriley)
42
+
43
+ [Compare v0.4.1...v0.4.2](https://github.com/dry-rb/dry-component/compare/v0.4.1...v0.4.2)
44
+
45
+ # 0.4.1 - 2016-07-26 [YANKED]
46
+
47
+ ### Fixed
48
+
49
+ - Require the 0.4.0 release of dry-auto_inject for the features below (in 0.4.0) to work properly (timriley)
50
+
51
+ [Compare v0.4.0...v0.4.1](https://github.com/dry-rb/dry-component/compare/v0.4.0...v0.4.1)
52
+
53
+ # 0.4.0 - 2016-07-26 [YANKED]
54
+
55
+ ### Added
56
+
57
+ - Support for supplying a default namespace to a container, which is passed to the container's injector to allow for convenient shorthand access to registered objects in the same namespace (timriley in [#20](https://github.com/dry-rb/dry-component/pull/20))
58
+
59
+ ```ruby
60
+ # Set up container with default namespace
61
+ module Admin
62
+ class Container < Dry::Component::Container
63
+ configure do |config|
64
+ config.root = Pathname.new(__dir__).join("../..")
65
+ config.default_namespace = "admin"
66
+ end
67
+ end
68
+
69
+ Import = Container.injector
70
+ end
71
+
72
+ module Admin
73
+ class CreateUser
74
+ # "users.repository" will resolve an Admin::Users::Repository instance,
75
+ # where previously you had to identify it as "admin.users.repository"
76
+ include Admin::Import["users.repository"]
77
+ end
78
+ end
79
+ ```
80
+
81
+ - Support for supplying to options directly to dry-auto_inject's `Builder` via `Dry::Component::Container#injector(options)`. This allows you to provide dry-auto_inject customizations like your own container of injection strategies (timriley in [#20](https://github.com/dry-rb/dry-component/pull/20))
82
+ - Support for accessing all available injector strategies, not just the defaults (e.g. `MyContainer.injector.some_custom_strategy`) (timriley in [#19](https://github.com/dry-rb/dry-component/pull/19))
83
+
84
+ ### Changed
85
+
86
+ - Subclasses of `Dry::Component::Container` no longer have an `Injector` constant automatically defined within them. The recommended approach is to save your own injector object to a constant, which allows you to pass options to it at the same time, e.g. `MyApp::Import = MyApp::Container.injector(my_options)` (timriley in [#19](https://github.com/dry-rb/dry-component/pull/19))
87
+
88
+ [Compare v0.3.0...v0.4.0](https://github.com/dry-rb/dry-component/compare/v0.3.0...v0.4.0)
89
+
90
+ # 0.3.0 - 2016-06-18
91
+
92
+ ### Changed
93
+
94
+ Removed two pieces that are moving to dry-web:
95
+
96
+ - Removed `env` setting from `Container` (timriley)
97
+ - Removed `Dry::Component::Config` and `options` setting from `Container` (timriley)
98
+ - Changed `Component#configure` behavior so it can be run multiple times for configuration to be applied in multiple passes (timriley)
99
+
100
+ [Compare v0.2.0...v0.3.0](https://github.com/dry-rb/dry-component/compare/v0.2.0...v0.3.0)
101
+
102
+ # 0.2.0 - 2016-06-13
103
+
104
+ ### Changed
105
+
106
+ - Component core directory is now `component/` by default (timriley)
107
+ - Injector default stragegy is now whatever dry-auto_inject's default is (rather than hard-coding a particular default strategy for dry-component) (timriley)
108
+
109
+ ### Fixed
110
+
111
+ - Fixed bug where specified auto-inject strategies were not respected (timriley)
112
+
113
+ [Compare v0.1.0...v0.2.0](https://github.com/dry-rb/dry-component/compare/v0.1.0...v0.2.0)
114
+
115
+ # 0.1.0 - 2016-06-07
116
+
117
+ ### Added
118
+
119
+ * Provide a dependency injector as an `Inject` constant inside any subclass of `Dry::Component::Container`. This injector supports all of `dry-auto_inject`'s default injection strategies, and will lazily load any dependencies as they are injected. It also supports arbitrarily switching strategies, so they can be used in different classes as required (e.g. `include MyComponent::Inject.args["dep"]`) (timriley)
120
+ * Support aliased dependency names when calling the injector object (e.g. `MyComponent::Inject[foo: "my_app.foo", bar: "another.thing"]`) (timriley)
121
+ * Allow a custom dependency loader to be set on a container via its config (AMHOL)
122
+
123
+ ```ruby
124
+ class MyContainer < Dry::Component::Container
125
+ configure do |config|
126
+ # other config
127
+ config.loader = MyLoader
128
+ end
129
+ end
130
+ ```
131
+
132
+ ### Changed
133
+
134
+ * `Container.boot` now only makes a simple `require` for the boot file (solnic)
135
+ * Container object is passed to `Container.finalize` blocks (solnic)
136
+ * Allow `Pathname` objects passed to `Container.require` (solnic)
137
+ * Support lazily loading missing dependencies from imported containers (solnic)
138
+ * `Container.import_module` renamed to `.injector` (timriley)
139
+ * Default injection strategy is now `kwargs`, courtesy of the new dry-auto_inject default (timriley)
140
+
141
+ [Compare v0.0.2...v0.1.0](https://github.com/dry-rb/dry-component/compare/v0.0.2...v0.1.0)
142
+
143
+ # 0.0.2 - 2015-12-24
144
+
145
+ ### Added
146
+
147
+ * Containers have a `name` setting (solnic)
148
+ * Containers can be imported into one another (solnic)
149
+
150
+ ### Changed
151
+
152
+ * Container name is used to determine the name of its config file (solnic)
153
+
154
+ [Compare v0.0.1...v0.0.2](https://github.com/dry-rb/dry-component/compare/v0.0.1...v0.0.2)
155
+
156
+ # 0.0.1 - 2015-12-24
157
+
158
+ First public release, extracted from rodakase project
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'codeclimate-test-reporter', platforms: :mri
6
+
7
+ group :tools do
8
+ gem 'byebug', platforms: :mri
9
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Dryrb Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ [gem]: https://rubygems.org/gems/dry-system
2
+ [travis]: https://travis-ci.org/dry-rb/dry-system
3
+ [gemnasium]: https://gemnasium.com/dry-rb/dry-system
4
+ [codeclimate]: https://codeclimate.com/github/dry-rb/dry-system
5
+ [coveralls]: https://coveralls.io/r/dry-rb/dry-system
6
+ [inchpages]: http://inch-ci.org/github/dry-rb/dry-system
7
+
8
+ # dry-system [![Join the chat at https://gitter.im/dry-rb/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dry-rb/chat)
9
+
10
+ [![Gem Version](https://badge.fury.io/rb/dry-system.svg)][gem]
11
+ [![Build Status](https://travis-ci.org/dry-rb/dry-system.svg?branch=master)][travis]
12
+ [![Dependency Status](https://gemnasium.com/dry-rb/dry-system.svg)][gemnasium]
13
+ [![Code Climate](https://codeclimate.com/github/dry-rb/dry-system/badges/gpa.svg)][codeclimate]
14
+ [![Test Coverage](https://codeclimate.com/github/dry-rb/dry-system/badges/coverage.svg)][codeclimate]
15
+ [![Inline docs](http://inch-ci.org/github/dry-rb/dry-system.svg?branch=master)][inchpages]
16
+
17
+ ## Links
18
+
19
+ * [Documentation](http://dry-rb.org/gems/dry-system)
20
+
21
+ ## LICENSE
22
+
23
+ See `LICENSE` file.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
5
+
6
+ require 'rspec/core'
7
+ require 'rspec/core/rake_task'
8
+
9
+ task default: :spec
10
+
11
+ desc 'Run all specs in spec directory'
12
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ require File.expand_path('../lib/dry/system/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'dry-system'
6
+ spec.version = Dry::System::VERSION
7
+ spec.authors = ['Piotr Solnica']
8
+ spec.email = ['piotr.solnica@gmail.com']
9
+ spec.summary = 'Organize your code into reusable components'
10
+ spec.homepage = 'http://dry-rb.org/gems/dry-system'
11
+ spec.license = 'MIT'
12
+
13
+ spec.files = `git ls-files -z`.split("\x0")
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.required_ruby_version = '>= 2.1.0'
19
+
20
+ spec.add_runtime_dependency 'inflecto', '>= 0.0.2'
21
+ spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
22
+ spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
23
+ spec.add_runtime_dependency 'dry-container', '~> 0.4'
24
+ spec.add_runtime_dependency 'dry-auto_inject', '>= 0.4.0'
25
+ spec.add_runtime_dependency 'dry-configurable', '~> 0.1'
26
+
27
+ spec.add_development_dependency 'bundler'
28
+ spec.add_development_dependency 'rake'
29
+ spec.add_development_dependency 'rspec'
30
+ end
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'dry-system', path: '../..'
4
+ gem 'sequel'
5
+ gem 'sqlite3'
@@ -0,0 +1,5 @@
1
+ require 'import'
2
+
3
+ class UserRepo
4
+ include Import['persistence.db']
5
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'system/container'
2
+
3
+ App.finalize!
4
+
5
+ user_repo = App['user_repo']
6
+
7
+ puts user_repo.db.inspect
@@ -0,0 +1,13 @@
1
+ App.finalize(:persistence) do |persistence|
2
+ init do
3
+ require 'sequel'
4
+ end
5
+
6
+ start do
7
+ persistence.register('persistence.db', Sequel.connect('sqlite::memory'))
8
+ end
9
+
10
+ stop do
11
+ db.close_connection
12
+ end
13
+ end