injectable 0.0.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dc9ea4f80413a4e20a767b34804610ef6f6c5e24ae1670e3ee74909a928d4d33
4
+ data.tar.gz: f52f528a69f32a026258dd36017762256b410ae954950629190845e752a68c06
5
+ SHA512:
6
+ metadata.gz: 87a1f36da87711d78b9fa8ac6bcc80d6f4fe107e44e0174d786472efe667d5423482c7250f474c92f59bdbca4c780ca4d3eef6403af3da2e9851a0963588c813
7
+ data.tar.gz: ce7a234c6105ac0e8eeb5804e8d304a13a343c39147d3df782073bb44603a65100666cbad7593f4319f84dc4803c6c5614d2789f933c85a83420fc67a32089cf
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 2.0.1
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at dev@rubiconmd.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in injectable.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ injectable (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (12.3.2)
11
+ rspec (3.8.0)
12
+ rspec-core (~> 3.8.0)
13
+ rspec-expectations (~> 3.8.0)
14
+ rspec-mocks (~> 3.8.0)
15
+ rspec-core (3.8.0)
16
+ rspec-support (~> 3.8.0)
17
+ rspec-expectations (3.8.3)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.8.0)
20
+ rspec-mocks (3.8.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.8.0)
23
+ rspec-support (3.8.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 2.0)
30
+ injectable!
31
+ rake (~> 12.0)
32
+ rspec (~> 3.0)
33
+
34
+ BUNDLED WITH
35
+ 2.0.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 amrocco
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,209 +1,358 @@
1
- Injectable [![Build Status](https://secure.travis-ci.org/durran/injectable.png?branch=master&.png)](http://travis-ci.org/durran/injectable) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/durran/injectable)
2
- ========
1
+ # Injectable
3
2
 
4
- Injectable is an extremely simple dependency injection framework for Ruby. It's
5
- stupid simple and experimental so don't expect support for now - but may turn out
6
- to be something in the future.
3
+ `Injectable` is an opinionated and declarative [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) library for ruby.
7
4
 
8
- Usage
9
- -----
5
+ It is being used in production (under ruby 2.5.1) in [RubiconMD](https://github.com/rubiconmd) and was extracted from its codebase.
10
6
 
11
- Say we have a `UserService` that has some basic logic for performing operations
12
- related to a `User` and a `FacebookService`. We can tell the `UserService` what
13
- its dependencies are via `Injectable`. Note that as of `0.0.2` all objects that
14
- can be injected into others must include the `Injectable` module.
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
15
10
 
16
11
  ```ruby
17
- class User
18
- include Injectable
12
+ gem 'injectable', '>= 1.0.0'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install injectable
22
+
23
+ ## Motivation
24
+
25
+ The main motivation of `Injectable` is to ease compliance with [SOLID's](https://en.wikipedia.org/wiki/SOLID)\*, [SRP](https://en.wikipedia.org/wiki/Single_responsibility_principle)\* and [Dependency Inversion principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle) by providing a declarative and very readable [DSL](https://en.wikipedia.org/wiki/Domain-specific_language)\* which avoids lots of bolierplate code and thus encourages good practices.*
26
+
27
+ *Sorry about the acronyms, but using an [Ubiquitous Language](https://martinfowler.com/bliki/UbiquitousLanguage.html) is important.
28
+
29
+ ### Encapsulate domain logic
30
+
31
+ Using Ruby on Rails recommended practices as an example, when your application grows enough you usually end up with huge model classes with too many responsibilities.
32
+
33
+ It's way better (although it requires effort and discipline) to split those models and extract domain logic into [Service Objects](https://martinfowler.com/bliki/AnemicDomainModel.html) ("SOs" from now on). You can do this without `Injectable`, but `Injectable` will make your SOs way more readable and a pleasure not only to write but also to test, while encouraging general good practices.
34
+
35
+ ### Avoiding to hardcode dependencies
36
+
37
+ If you find occurences of `SomeClass.any_instance.expects(:method)` in your **unit** tests, then you are probably hardcoding dependencies:
38
+
39
+ ```rb
40
+ test "MyClass#call"
41
+ Collaborator.any_instance.expects(:submit!) # hardcoded dependency
42
+ MyClass.new.call
19
43
  end
20
44
 
21
- class FacebookService
22
- include Injectable
45
+ class MyClass
46
+ attr_reader :collaborator
47
+
48
+ def initialize
49
+ @collaborator = Collaborator.new
50
+ end
51
+
52
+ def call
53
+ collaborator.submit!
54
+ end
23
55
  end
56
+ ```
24
57
 
25
- class UserService
26
- include Injectable
27
- dependencies :user, :facebook_service
58
+ What if you did this instead:
59
+
60
+ ```rb
61
+ test "MyClass#call"
62
+ collaborator = stub('Collaborator')
63
+ collaborator.expects(:submit!)
64
+ MyClass.new(collaborator: collaborator).call
65
+ end
66
+
67
+ class MyClass
68
+ attr_reader :collaborator
69
+
70
+ def initialize(collaborator: Collaborator.new) # we will just provide a default
71
+ @collaborator = collaborator
72
+ end
73
+
74
+ def call
75
+ collaborator.submit!
76
+ end
28
77
  end
29
78
  ```
30
79
 
31
- The `UserService` would then get a constructor defined that takes a `User` and
32
- `FacebookService` as its arguments:
80
+ The benefits are not only for testing, as now your class is more modular and you can swap collaborators as long as they have the proper interface, in this case they have to `respond_to :submit!`
33
81
 
34
- ```ruby
35
- user = User.new
36
- facebook_service = FacebookService.new
37
- user_service = UserService.new(user, facebook_service)
82
+ `Injectable` allows you to write the above code like this:
83
+
84
+ ```rb
85
+ class MyClass
86
+ include Injectable
87
+
88
+ dependency :collaborator
89
+
90
+ def call
91
+ collaborator.submit!
92
+ end
93
+ end
38
94
  ```
39
95
 
40
- Reader methods are also automatically provided for each dependency:
96
+ It might not seem a lot but:
41
97
 
42
- ```ruby
43
- user_service.user
44
- user_service.facebook_service
98
+ 1. Imagine that you have 4 dependencies. That's a lot of boilerplate.
99
+ 2. `Injectable` is not only this, it has many more features. Please keep reading.
100
+
101
+ ## Usage example
102
+
103
+ `Injectable` is a mixin that you have to include in your class and it will provide several macros.
104
+
105
+ This is a real world example:
106
+
107
+ ```rb
108
+ class PdfGenerator
109
+ include Injectable
110
+
111
+ dependency :wicked_pdf
112
+
113
+ argument :html
114
+ argument :render_footer, default: false
115
+
116
+ def call
117
+ wicked_pdf.pdf_from_string(html, options)
118
+ end
119
+
120
+ private
121
+
122
+ def options
123
+ return {} unless render_footer
124
+
125
+ {
126
+ footer: {
127
+ left: footer,
128
+ }
129
+ }
130
+ end
131
+
132
+ def footer
133
+ "Copyright ® #{Time.current.year}"
134
+ end
135
+ end
136
+
137
+ # And you would use it like this:
138
+ PdfGenerator.call(html: '<some html here>')
139
+ # Overriding the wicked_pdf dependency:
140
+ PdfGenerator.new(wicked_pdf: wicked_pdf_replacement).call(html: '<some html>')
45
141
  ```
46
142
 
47
- Say we just want to throw a bunch of objects in a container, and ask for an
48
- object of a specific type and let the container figure out the dependencies:
143
+ ## Premises
49
144
 
50
- ```ruby
51
- user = User.new
52
- facebook_service = FacebookService.new
53
- container = Injectable::Container.new(user, facebook_service)
54
- user_service = container.get(:user_service)
145
+ In order to understand how (and why) `Injectable` works, you need to know some principles.
146
+
147
+ ### #1 The `#call` method
148
+
149
+ `Injectable` classes **must define a public `#call` method that takes no arguments**.
150
+
151
+ This is **the only public method** you will be defining in your `Injectable` classes.
152
+
153
+ ```rb
154
+ # Correct ✅
155
+ def call
156
+ # do stuff
157
+ end
158
+
159
+ # Wrong ❗️
160
+ def call(some_argument)
161
+ # won't work and will raise an exception at runtime
162
+ end
55
163
  ```
56
164
 
57
- Objects can also be added to the container post instantiation.
165
+ If you want your `#call` method to receive arguments, that's what the `#argument` macro is for. BTW, we call those **runtime arguments**.
58
166
 
59
- ```ruby
60
- user = User.new
61
- facebook_service = FacebookService.new
62
- container = Injectable::Container.new
63
- container.put(user, facebook_service)
64
- user_service = container.get(:user_service)
167
+ Why `#call`?
168
+
169
+ Because it's a ruby idiom. Many things in ruby are `callable`, like lambdas.
170
+
171
+ ### #2 The `initialize` method
172
+
173
+ Injectable classes take their **dependencies as keyword arguments** on the `initialize` method. They can also take **configuration arguments** on `initialize`:
174
+
175
+ ```rb
176
+ MyClass.new(some_dep: some_dep_instance, some_config: true).call
65
177
  ```
66
178
 
67
- Since `User` and `FacebookService` take no arguments, we don't even need to
68
- pass them into the container - it will automatically instantiate new ones:
179
+ `Injectable` instantiates **dependencies that you have declared with the `dependency` macro** for you and passes them to `initialize`, so if you don't want to override those you don't even need to instantiate the class and you can use the provided class method **`#call` shortcut**:
69
180
 
70
- ```ruby
71
- container = Injectable::Container.new
72
- user = container.get(:user)
73
- user_service = container.get(:user_service)
181
+ ```rb
182
+ Myclass.call # This is calling `initialize` under the hood
74
183
  ```
75
184
 
76
- Injectable also supports depending on roles rather than concrete classes by
77
- allowing the registration of classes whose instances perform that role. An
78
- implementation can be registered on a single container itself as a "one off":
185
+ If you need to override dependencies or configuration options, just call `new` yourself:
79
186
 
80
- ```ruby
81
- container = Injectable::Container.new
82
- container.register_implementation(:facebook_service, DifferentFacebookService)
83
- user_service = container.get(:user_service)
84
- # `user_service`'s facebook_service will be an instance of DifferentFacebookService
187
+ ```rb
188
+ Myclass.new(some_dep: Override.new, some_config: false).call
85
189
  ```
86
190
 
87
- You can also define concrete implementations at the global level via `configure`:
191
+ If you do that, **any dependency that you didn't pass will be injected by `Injectable`**.
192
+ Notice that **configuration arguments**, which are declared with `#initialize_with` behave in the exact same way.
88
193
 
89
- ```ruby
90
- Injectable.configure do |config|
91
- config.register_implementation(:facebook_service, DifferentFacebookService)
92
- end
194
+ ### #3 Keyword arguments
93
195
 
94
- container = Injectable::Container.new
95
- user_service = container.get(:user_service)
96
- # `user_service`'s facebook_service will be an instance of DifferentFacebookService
97
- ```
196
+ Both `#initialize` and `#call` take **keyword arguments**.
98
197
 
99
- Multiple implementations for the same role can be configured - the rules on how
100
- they will be used are as follows: Check for an already instantiated instance in
101
- the container. If one or both exist, take the first. If none exist, then attempt to
102
- resolve the dependency with each registered role until one succeeds. An example:
198
+ ### #4 Readers
103
199
 
104
- ```ruby
105
- module Portable
106
- def charge
107
- # Some logic here.
108
- end
109
- end
200
+ All `Injectable` macros define reader methods for you, that's why you define `#call` without arguments, because **you access everything you declare via reader methods**.
110
201
 
111
- class Phone
112
- include Injectable
113
- include Portable
114
- end
202
+ ## The `#dependency` macro
115
203
 
116
- class Tablet
117
- include Injectable
118
- include Portable
204
+ This is the main reason why you want to use this library in the first place.
205
+
206
+ There are several ways of declaring a `#dependency`:
207
+
208
+ ### Bare dependency name
209
+
210
+ ```rb
211
+ class ReportPdfRenderer
212
+ include Injectable
213
+
214
+ dependency :some_dependency
119
215
  end
216
+ ```
217
+
218
+ 1. `Injectable` first tries to find the `SomeDependency` constant in `ReportPdfRenderer`namespace.
219
+ 2. If it doesn't find it, then tries without namespace (`::SomeDependency`).
220
+
221
+ Notice that this happens **at runtime**, not when defining your class.
120
222
 
121
- class Application
223
+ ### Explicit, inline class:
224
+
225
+ ```rb
226
+ class MyInjectable
122
227
  include Injectable
123
- dependencies :portable
228
+
229
+ dependency :client, class: Aws::S3::Client
230
+ dependency :parser, class: VeryLongClassNameForMyParser
124
231
  end
232
+ ```
233
+
234
+ Nothing fancy here, you are explicitly telling `Injectable` which class to instantiate for you.
235
+
236
+ You will want to use this style for example if the class is namespaced somewhere else or if you want a different name other than the class', like for example if it's too long.
125
237
 
126
- Injectable.configure do |config|
127
- config.register_implementation(:portable, Phone, Tablet)
238
+ Notice that this approach sets the class when ruby interprets the class, **not at runtime**.
239
+
240
+ ### With a block:
241
+
242
+ ```rb
243
+ dependency :complex_client do
244
+ instance = ThirdPartyLib.new(:foo, bar: 'goo')
245
+ instance.set_config(:name, 'value')
246
+ instance
128
247
  end
248
+ ```
249
+
250
+ It's important to understand that `Injectable` won't call `#new` on whatever you return from this block.
251
+
252
+ You probably want to use this when your dependency has a complex setup. We use it a lot when wrapping third party libraries which aren't reused elsewhere.
253
+
254
+ If you want to wrap a third party library and you need to reuse it, then we recommend that you write a specific `Injectable` class for it, so it adheres to its principles and is easier to use.
255
+
256
+ ### `#dependency` options
257
+
258
+ #### `:with`
129
259
 
130
- container = Injectable::Container.new
131
- application = container.get(:application)
132
- application.portable #=> Returns a new Phone.
260
+ If the dependency takes arguments, you can set them with :with
133
261
 
134
- tablet = Tablet.new
135
- container = Injectable::Container.new(tablet)
136
- application = container.get(:application)
137
- application.portable #=> Returns the existing instance of a Tablet.
262
+ ```rb
263
+ # Arrays will be splatted: WithNormalArguments.new(1, 2, 3)
264
+ dependency :with_normal_arguments, with: [1, 2, 3]
265
+ # Hashes will be passed as-is: WithKeywordArguments.new(foo: 'bar)
266
+ dependency :with_keyword_arguments, with: { foo: 'bar' }
138
267
  ```
139
268
 
140
- Setter injection is not supported.
269
+ ### `:depends_on`
141
270
 
142
- How about the real world
143
- ------------------------
271
+ It allows you to share **memoized instances** of dependencies and supports both a single dependency or multiples as an Array:
144
272
 
145
- Let's look at the above classes, but say we're in a Rails application:
273
+ ```rb
274
+ dependency :client # this will be instantiated just once and will be shared
275
+ dependency :reporter, depends_on: :client
276
+ dependency :mailer, depends_on: %i[client reporter]
277
+ ```
146
278
 
147
- ```ruby
148
- class User < ActiveRecord::Base
149
- include Injectable
279
+ Dependencies of dependencies will be passed as keyword arguments using the same name they were declared with. In the example above, `Injectable` will instantiate a `Mailer` class passing `{ client: client, reporter: reporter }` to `#initialize`.
280
+
281
+ If you have a dependency that is defined with a block which also depends_on other dependencies, you'll receive those as keyword arguments:
282
+
283
+ ```rb
284
+ dependency :my_dependency, depends_on: :client do |client:|
285
+ MyDependency.new(client)
150
286
  end
287
+ ```
151
288
 
152
- class FacebookService
153
- include Injectable
289
+ ### `:call`
154
290
 
155
- def post_to_wall(id, message)
156
- # ...
157
- end
291
+ Sometimes you have a class that doesn't adhere to `Injectable` principles:
292
+
293
+ ```rb
294
+ dependency :renderer
295
+
296
+ def call
297
+ renderer.render # this class does not respond to `call`
158
298
  end
299
+ ```
159
300
 
160
- class UserService
161
- include Injectable
162
- dependencies :user, :facebook_service
301
+ `:call` is a way of wrapping such dependency so it behaves like an `Injectable`:
163
302
 
164
- def post_to_wall(message)
165
- facebook_service.post_to_wall(user.id, message)
166
- end
303
+ ```rb
304
+ dependency :renderer, call: :render
305
+
306
+ def call
307
+ renderer.call
167
308
  end
168
309
  ```
169
310
 
170
- Now in our controller, we can just create a new container the user we find
171
- and then ask the container to do all the other work. This is more closely
172
- related to what one might do in a real application.
311
+ It's important to understand that **you can mix and match all dependency configurations and options** described above.
173
312
 
174
- ```ruby
175
- class UsersController < ApplicationController
313
+ ## `#initialize_with` macro
176
314
 
177
- def post_to_wall
178
- container.get(:user_service).post_to_wall(params[:message])
179
- respond_with container.get(:user)
180
- end
315
+ This macro is meant for **configuration arguments** passed to `initialize`:
181
316
 
182
- private
317
+ ```rb
318
+ initialize_with :debug, default: false
319
+ ```
183
320
 
184
- def container
185
- @container ||= Injectable::Container.new(User.find(params[:id]))
186
- end
187
- end
321
+ If you don't pass the `:default` option the argument will be required.
322
+
323
+ ## `#argument` macro
324
+
325
+ `#argument` allows you to define **runtime arguments** passed to `#call`
326
+
327
+ ```rb
328
+ argument :browser, default: 'Unknown'
188
329
  ```
189
330
 
190
- Copyright (c) 2012 Durran Jordan
331
+ If you don't pass the `:default` option the argument will be required.
332
+
333
+
334
+ ## Development
335
+
336
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
337
+
338
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
339
+
340
+ ## Contributing
341
+
342
+ Bug reports and pull requests are welcome on GitHub at https://github.com/rubiconmd/injectable. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
343
+
344
+ ## License
345
+
346
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
347
+
348
+ ## Code of Conduct
191
349
 
192
- Permission is hereby granted, free of charge, to any person obtaining
193
- a copy of this software and associated documentation files (the
194
- "Software"), to deal in the Software without restriction, including
195
- without limitation the rights to use, copy, modify, merge, publish,
196
- distribute, sublicense, and/or sell copies of the Software, and to
197
- permit persons to whom the Software is furnished to do so, subject to
198
- the following conditions:
350
+ Everyone interacting in the Injectable project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
199
351
 
200
- The above copyright notice and this permission notice shall be
201
- included in all copies or substantial portions of the Software.
352
+ ## Credits
202
353
 
203
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
204
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
205
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
206
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
207
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
208
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
209
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
354
+ - [RubiconMD](https://github.com/rubiconmd) allowed extracting this gem from its codebase and release it as open source.
355
+ - [Durran Jordan](https://github.com/durran) allowed the usage of the gem name at rubygems.org.
356
+ - [David Marchante](https://github.com/iovis9) brainstormed the `initialize`/`call` approach, did all code reviews and provided lots of insightful feedback and suggestions. He also wrote the inline documentation.
357
+ - [Julio Antequera](https://github.com/jantequera), [Jimmi Carney](https://github.com/ayoformayo) and [Anthony Rocco](https://github.com/amrocco) had the patience to use it and report many bugs. Also most of the features in this gem came up when reviewing their usage of it. Anthony also made the effort of extracting the code from RubiconMD's codebase.
358
+ - [Rodrigo Álvarez](https://github.com/Papipo) had the idea for the DSL and actually wrote the library.