canister 0.9.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
+ SHA1:
3
+ metadata.gz: 8d69f8befb7b0da9e4d982db5a64988fcc6d540e
4
+ data.tar.gz: e4cd5da5bfc6cfad289ede2651b55ccaeb165f8e
5
+ SHA512:
6
+ metadata.gz: ece48adf544fa81cae520ded5e0ec262090d257ada284449c4b59702a8e20c34c1e4e55c8273f57905be2e8791d4032ac03feb94c22dfe01f06e0ec46b84e775
7
+ data.tar.gz: cea1b3678cd466155d63e3ab6bff4b4ea0fd82eeda8e22a0a36a660f9b5e1cf046cd8e3ecdc8f17db32021c0c3752e843d4102cc4c9f99d5f626610c83d3efb7
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /Gemfile.lock
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,144 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ DisplayCopNames: true
5
+ TargetRubyVersion: 2.3
6
+ Exclude:
7
+ - '*.gemspec'
8
+
9
+ Naming/FileName:
10
+ ExpectMatchingDefinition: true
11
+ Exclude:
12
+ - 'bin/**/*'
13
+ - 'spec/**/*'
14
+ - 'lib/*/version.rb'
15
+
16
+ Style/Documentation:
17
+ Exclude:
18
+ - 'spec/**/*'
19
+
20
+ # We disable this cop because we want to use Pathname#/
21
+ # and this cop is not configurable at all.
22
+ Layout/SpaceAroundOperators:
23
+ Enabled: false
24
+
25
+ Security/YAMLLoad:
26
+ Exclude:
27
+ - 'spec/**/*'
28
+
29
+ Style/Alias:
30
+ EnforcedStyle: prefer_alias_method
31
+
32
+ Metrics/LineLength:
33
+ Max: 100
34
+ AllowHeredoc: true
35
+ AllowURI: true
36
+ URISchemes:
37
+ - http
38
+ - https
39
+
40
+ Metrics/BlockLength:
41
+ Exclude:
42
+ - 'spec/**/*_spec.rb'
43
+
44
+ Layout/ElseAlignment:
45
+ Enabled: false
46
+
47
+ Layout/FirstParameterIndentation:
48
+ EnforcedStyle: consistent
49
+
50
+ Layout/AlignParameters:
51
+ EnforcedStyle: with_fixed_indentation
52
+
53
+ Layout/CaseIndentation:
54
+ EnforcedStyle: end
55
+
56
+ Layout/ClosingParenthesisIndentation:
57
+ Enabled: false
58
+
59
+ Style/ClassAndModuleChildren:
60
+ EnforcedStyle: nested
61
+
62
+ Style/CommentAnnotation:
63
+ Enabled: false
64
+
65
+ # Does not work for multi-line copyright notices.
66
+ Style/Copyright:
67
+ Enabled: false
68
+
69
+ Layout/EmptyLineBetweenDefs:
70
+ AllowAdjacentOneLineDefs: true
71
+
72
+ # These two cops do not differentiate between the scope the file is describing
73
+ # and any namespaces it is nested under. If this is not acceptable,
74
+ # no_empty_lines produces the least offensive results.
75
+ Layout/EmptyLinesAroundClassBody:
76
+ Enabled: false
77
+ Layout/EmptyLinesAroundModuleBody:
78
+ Enabled: false
79
+
80
+ # Produces poor results.
81
+ Style/GuardClause:
82
+ Enabled: false
83
+
84
+ Style/IfUnlessModifier:
85
+ Enabled: false
86
+
87
+ Layout/IndentArray:
88
+ EnforcedStyle: consistent
89
+
90
+ Layout/IndentHash:
91
+ EnforcedStyle: consistent
92
+
93
+ Layout/AlignHash:
94
+ EnforcedColonStyle: table
95
+ EnforcedHashRocketStyle: table
96
+ EnforcedLastArgumentHashStyle: always_ignore
97
+
98
+ Layout/MultilineMethodCallIndentation:
99
+ EnforcedStyle: indented
100
+
101
+ Layout/MultilineOperationIndentation:
102
+ EnforcedStyle: indented
103
+
104
+ # Produces poor results.
105
+ Style/Next:
106
+ Enabled: false
107
+
108
+ Style/RedundantReturn:
109
+ AllowMultipleReturnValues: true
110
+
111
+ Style/RegexpLiteral:
112
+ AllowInnerSlashes: true
113
+
114
+ Style/Semicolon:
115
+ AllowAsExpressionSeparator: true
116
+
117
+ Style/StringLiterals:
118
+ EnforcedStyle: double_quotes
119
+
120
+ Style/StringLiteralsInInterpolation:
121
+ EnforcedStyle: double_quotes
122
+
123
+ Layout/SpaceInsideBlockBraces:
124
+ SpaceBeforeBlockParameters: false
125
+
126
+ Style/SymbolArray:
127
+ EnforcedStyle: brackets
128
+
129
+ Lint/BlockAlignment:
130
+ EnforcedStyleAlignWith: start_of_block
131
+ #EnforcedStyleAlignWith: start_of_line
132
+
133
+ Lint/EndAlignment:
134
+ EnforcedStyleAlignWith: start_of_line
135
+
136
+ Lint/DefEndAlignment:
137
+ EnforcedStyleAlignWith: def
138
+
139
+ Performance/RedundantMerge:
140
+ Enabled: false
141
+
142
+ Style/WordArray:
143
+ EnforcedStyle: brackets
144
+
data/.rubocop_todo.yml ADDED
File without changes
data/.travis.yml ADDED
@@ -0,0 +1,28 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4
5
+ - 2.3
6
+
7
+ branches:
8
+ only:
9
+ - master
10
+ - develop
11
+
12
+ env:
13
+ global:
14
+ - CC_TEST_REPORTER_ID=a492448053c934b2a3cfa2f86f3357491d11beda5499db7884ae13859870fd29
15
+
16
+ before_install: gem install bundler
17
+
18
+ before_script:
19
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
20
+ - chmod +x ./cc-test-reporter
21
+ - ./cc-test-reporter before-build
22
+
23
+ script:
24
+ - bundle exec rspec --order=random
25
+
26
+ after_script:
27
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT || true
28
+
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in closet.gemspec
8
+ gemspec
9
+
10
+ group :development, :test do
11
+ gem "pry"
12
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2018, The Regents of the University of Michigan.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are
6
+ met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ * Neither the name of the The University of Michigan nor the
14
+ names of its contributors may be used to endorse or promote products
15
+ derived from this software without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF MICHIGAN AND
18
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE
21
+ UNIVERSITY OF MICHIGAN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23
+ TO,PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Canister
2
+
3
+ [![Build Status](https://travis-ci.org/mlibrary/canister.svg?branch=master)](https://travis-ci.org/mlibrary/canister)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/590e17334ea92100e297/maintainability)](https://codeclimate.com/github/mlibrary/canister/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/590e17334ea92100e297/test_coverage)](https://codeclimate.com/github/mlibrary/canister/test_coverage)
6
+
7
+
8
+ ## Summary
9
+
10
+ Canister is a simple IoC container for ruby. It has no dependencies and provides only
11
+ the functionality you need. It does not monkey-patch ruby or pollute the global
12
+ namespace, and most importantly *it expects to be invisible to your domain classes.*
13
+
14
+ It provides:
15
+
16
+ * Out-of-order declaration
17
+ * Caching
18
+ * Automatic dependency resolution
19
+ * Automatic cache invalidation on re-registration
20
+
21
+ ## Why do I need this? Especially in ruby?
22
+
23
+ Canister was created to make it easier to declare our setup for our application's
24
+ production and test environments in a single place, without needing to know
25
+ when exactly those objects were created.
26
+
27
+ *Canister is not a replacement for
28
+ dependency injection.* Rather, it is useful when you have designed your objects
29
+ to have their dependencies injected. For example, it would be a *mistake* to write
30
+ all of your classes such that they except a single parameter called `container`.
31
+
32
+ For more information on dependency injection and inversion of control containers in
33
+ ruby, please see
34
+ [this excellent article](https://gist.github.com/malakai97/b1d3bdf6d80c6f99a875930981243f9d)
35
+ by [Blair Anderson](https://github.com/blairanderson) that both sums up the issue
36
+ and was the inspiration for this gem.
37
+
38
+
39
+ ## Installation
40
+
41
+ Add it to your Gemfile and you're off to the races.
42
+
43
+ ## Usage
44
+
45
+ ```ruby
46
+ # Basic usage
47
+ container = Canister.new
48
+ container.register(:foo) { "foo" }
49
+ container.register(:bar) {|c| c.foo + "bar" }
50
+
51
+ container.bar #=> "foobar"
52
+ container[:bar] #=> "foobar"
53
+ container["bar"] #=> "foobar"
54
+
55
+ # Dependencies can be declared in any order
56
+ container.register(:after) {|c| "#{c.before} and after" }
57
+ container.register(:before) { "before" }
58
+ container.after #=> "before and after"
59
+
60
+ # Values are cached
61
+ container.register(:wait) { sleep 3; 27 }
62
+ container.wait
63
+ .
64
+ .
65
+ .
66
+ #=================> 27
67
+ container.wait #=> 27
68
+
69
+ # Caches are invalidated automatically
70
+ container.register(:foo) { "oof" }
71
+ container.bar #=> "oofbar"
72
+ ```
73
+
74
+ ## Contributing
75
+
76
+ Standard rules apply.
77
+
78
+ ## Compatibility
79
+
80
+ * ruby 2.3.x
81
+ * ruby 2.4.x
82
+
83
+ As Canister does not rely on any specific runtime environment other than
84
+ the ruby core, it is compatible with every ruby library and framework.
85
+
86
+ ## Authors
87
+
88
+ * The author and maintainer is [Bryan Hockey](https://github.com/malakai97)
89
+ * This project was inspired by
90
+ [this excellent article](https://gist.github.com/malakai97/b1d3bdf6d80c6f99a875930981243f9d)
91
+ by [Blair Anderson](https://github.com/blairanderson). (We are not affiliated, so
92
+ don't blame him if this breaks.)
93
+
94
+ ## License
95
+
96
+ Copyright (c) 2018 The Regents of the University of Michigan.
97
+ All Rights Reserved.
98
+ Licensed according to the terms of the Revised BSD License.
99
+ See LICENSE.md for details.
100
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/canister.gemspec ADDED
@@ -0,0 +1,33 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "canister/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "canister"
8
+ spec.version = Canister::VERSION
9
+ spec.authors = ["Bryan Hockey"]
10
+ spec.email = ["bhock@umich.edu"]
11
+
12
+ spec.summary = %q{A simple IoC container for ruby.}
13
+ spec.description = %q{
14
+ Canister is a simple IoC container for ruby. It has no dependencies and provides only
15
+ the functionality you need. It does not monkey-patch ruby or pollute the global
16
+ namespace, and most importantly it expects to be invisible to your domain classes.
17
+ }
18
+ spec.homepage = "https://github.com/mlibrary/canister"
19
+ spec.license = "Revised BSD"
20
+
21
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
22
+ f.match(%r{^(test|spec|features)/})
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.16"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ spec.add_development_dependency "rubocop"
32
+ spec.add_development_dependency "simplecov"
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Canister
4
+ VERSION = "0.9.0"
5
+ end
data/lib/canister.rb ADDED
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "canister/version"
4
+
5
+ # A container that registers keys to values that are
6
+ # resolved at runtime. This allows for out-of-order declaration,
7
+ # automatic dependency resolution, and--upon
8
+ # redeclaration--automatic dependency cache invalidation.
9
+ class Canister
10
+
11
+ def initialize
12
+ @stack = []
13
+ @registry = {}
14
+ @resolved = {}
15
+ @dependents = Hash.new do |hash, key|
16
+ hash[key] = []
17
+ end
18
+ yield self if block_given?
19
+ end
20
+
21
+ # We override method_missing to enable dot notation
22
+ # for accessing registered values.
23
+ def method_missing(method, *args, &block)
24
+ if handles?(method)
25
+ resolve(method)
26
+ else
27
+ super(method, *args, block)
28
+ end
29
+ end
30
+
31
+ # We override respond_to? to enable dot notation
32
+ # for accessing registered values.
33
+ def respond_to_missing?(method, include_all = false)
34
+ handles?(method) || super(method, include_all)
35
+ end
36
+
37
+ # Register a value to a key by passing a block. Note that
38
+ # the value will be that returned by the block. If the key
39
+ # has been registered before, the old registration is
40
+ # overwritten. Dependents of the original registration
41
+ # are automatically invalidated.
42
+ # @param key [Symbol]
43
+ # @yield self [Container] Yields this container.
44
+ # @return the value defined in the block
45
+ def register(key, &block)
46
+ invalidate(key) if registered?(key)
47
+ registry[key.to_sym] = block
48
+ self
49
+ end
50
+
51
+ # Recursively resolves the object that was registered to
52
+ # the key. This value is memoized.
53
+ # @param key [Symbol]
54
+ def resolve(key)
55
+ add_dependent(key)
56
+ stack << key
57
+ value = resolved[key.to_sym] ||= registry[key.to_sym].call(self)
58
+ stack.pop
59
+ value
60
+ end
61
+ alias_method :[], :resolve
62
+
63
+ def keys
64
+ registry.keys
65
+ end
66
+
67
+ private
68
+
69
+ attr_reader :dependents, :registry, :resolved, :stack
70
+
71
+ def handles?(method)
72
+ registered?(method)
73
+ end
74
+
75
+ def add_dependent(key)
76
+ unless stack.empty?
77
+ dependents[key.to_sym] << stack.last
78
+ end
79
+ end
80
+
81
+ def registered?(key)
82
+ registry.key?(key.to_sym)
83
+ end
84
+
85
+ def unresolve(key)
86
+ resolved.delete(key.to_sym)
87
+ end
88
+
89
+ def invalidate(key, first = true)
90
+ unresolve(key)
91
+ dependents[key.to_sym]
92
+ .each {|child| invalidate(child, false) }
93
+ dependents.delete(key.to_sym) if first
94
+ end
95
+
96
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: canister
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Hockey
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-02-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: "\n Canister is a simple IoC container for ruby. It has no dependencies
84
+ and provides only\n the functionality you need. It does not monkey-patch ruby
85
+ or pollute the global\n namespace, and most importantly it expects to be invisible
86
+ to your domain classes.\n "
87
+ email:
88
+ - bhock@umich.edu
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - ".rspec"
95
+ - ".rubocop.yml"
96
+ - ".rubocop_todo.yml"
97
+ - ".travis.yml"
98
+ - Gemfile
99
+ - LICENSE.md
100
+ - README.md
101
+ - Rakefile
102
+ - canister.gemspec
103
+ - lib/canister.rb
104
+ - lib/canister/version.rb
105
+ homepage: https://github.com/mlibrary/canister
106
+ licenses:
107
+ - Revised BSD
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.6.13
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: A simple IoC container for ruby.
129
+ test_files: []