uses 1.0.0.pre.beta1
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.
- checksums.yaml +7 -0
- data/.circleci/config.yml +35 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +5 -0
- data/Gemfile +6 -0
- data/LICENSE.md +33 -0
- data/README.md +368 -0
- data/Rakefile +2 -0
- data/bin/ci +10 -0
- data/bin/console +14 -0
- data/bin/rspec +29 -0
- data/bin/setup +6 -0
- data/lib/uses/circular_dependency/analyzer.rb +60 -0
- data/lib/uses/circular_dependency/base_notifier.rb +18 -0
- data/lib/uses/circular_dependency/error.rb +7 -0
- data/lib/uses/circular_dependency/ignore_notifier.rb +10 -0
- data/lib/uses/circular_dependency/log_notifier.rb +10 -0
- data/lib/uses/circular_dependency/raise_error_notifier.rb +11 -0
- data/lib/uses/config.rb +38 -0
- data/lib/uses/error.rb +4 -0
- data/lib/uses/initializer/base_initializer.rb +19 -0
- data/lib/uses/initializer/from_initializers.rb +9 -0
- data/lib/uses/initializer/new_no_args.rb +11 -0
- data/lib/uses/initializer/proc_based.rb +7 -0
- data/lib/uses/initializer.rb +35 -0
- data/lib/uses/inject_double.rb +76 -0
- data/lib/uses/invalid_method_name.rb +5 -0
- data/lib/uses/method.rb +87 -0
- data/lib/uses/method_name.rb +23 -0
- data/lib/uses/uses_method_args.rb +24 -0
- data/lib/uses/version.rb +3 -0
- data/lib/uses.rb +49 -0
- data/uses.gemspec +29 -0
- metadata +138 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative "log_notifier"
|
2
|
+
require_relative "ignore_notifier"
|
3
|
+
require_relative "raise_error_notifier"
|
4
|
+
|
5
|
+
module Uses
|
6
|
+
module CircularDependency
|
7
|
+
class Analyzer
|
8
|
+
def initialize(uses_method_args)
|
9
|
+
@uses_method_args = uses_method_args
|
10
|
+
end
|
11
|
+
|
12
|
+
def analyze!
|
13
|
+
@dependency, @path_to_dependency = transitive_dependency?(@uses_method_args.klass_with_uses,@uses_method_args.klass_being_used)
|
14
|
+
end
|
15
|
+
|
16
|
+
def circular_dependency?
|
17
|
+
!!@dependency
|
18
|
+
end
|
19
|
+
|
20
|
+
def notify!
|
21
|
+
raise "You have not called analyze!" if @dependency.nil?
|
22
|
+
notifier = case @uses_method_args.uses_config.on_circular_dependency
|
23
|
+
when :warn then Uses::CircularDependency::LogNotifer.new(@uses_method_args, @path_to_dependency)
|
24
|
+
when :ignore then Uses::CircularDependency::IgnoreNotifier.new(@uses_method_args, @path_to_dependency)
|
25
|
+
when :raise_error then Uses::CircularDependency::RaiseErrorNotifier.new(@uses_method_args, @path_to_dependency)
|
26
|
+
end
|
27
|
+
notifier.notify!
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def transitive_dependency?(klass_with_uses,klass_being_analyzed, path=[])
|
33
|
+
other_class_has_uses = klass_being_analyzed.respond_to?(:__uses_dependent_classes)
|
34
|
+
|
35
|
+
if other_class_has_uses
|
36
|
+
if klass_with_uses == klass_being_analyzed
|
37
|
+
[ true, path ]
|
38
|
+
else
|
39
|
+
# Want to stop searching as soon as we find something
|
40
|
+
procs_to_check_for_transitive_dependencies = klass_being_analyzed.__uses_dependent_classes.keys.map { |klass|
|
41
|
+
->() { transitive_dependency?(klass_with_uses,klass, path + [ klass_being_analyzed ]) }
|
42
|
+
}
|
43
|
+
first_proc_to_find_a_dependency = procs_to_check_for_transitive_dependencies.detect { |p|
|
44
|
+
transitive_dependency, _ = p.()
|
45
|
+
transitive_dependency
|
46
|
+
}
|
47
|
+
if first_proc_to_find_a_dependency
|
48
|
+
_, path_to_dependency = first_proc_to_find_a_dependency.()
|
49
|
+
[ true, path_to_dependency ]
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Uses
|
2
|
+
module CircularDependency
|
3
|
+
class BaseNotifier
|
4
|
+
def initialize(uses_method_args, path_to_dependency)
|
5
|
+
path = if path_to_dependency.empty?
|
6
|
+
nil
|
7
|
+
else
|
8
|
+
" via #{path_to_dependency.map(&:to_s).join(',')}"
|
9
|
+
end
|
10
|
+
@message = "#{uses_method_args.klass_being_used} and #{uses_method_args.klass_with_uses} have a circular dependency#{path}. This may cause unforseen issues, or just be generally confusing"
|
11
|
+
end
|
12
|
+
|
13
|
+
def notify!
|
14
|
+
raise "subclass must implement"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/uses/config.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "active_support/core_ext/object/inclusion"
|
2
|
+
module Uses
|
3
|
+
class Config
|
4
|
+
# Configure what should happen when a circular dependency is detected.
|
5
|
+
#
|
6
|
+
# :warn:: Emit a warning, but allow it (default)
|
7
|
+
# :raise_error:: Raise an exception, effectively making your app unusable until
|
8
|
+
# you resolve the circular dependencies
|
9
|
+
# :ignore:: Emit a warning at DEBUG level, effectively allowing you to ignore these issues.
|
10
|
+
attr_reader :on_circular_dependency
|
11
|
+
|
12
|
+
# The array of custom initializers. Generally you should use
|
13
|
+
# `Uses.initializers do |initializers|` to manipulate this
|
14
|
+
attr_reader :initializers
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
reset!
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset!
|
21
|
+
self.on_circular_dependency = :warn
|
22
|
+
@initializers = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
ON_CIRCULAR_DEPENDENCY_VALUES = [
|
26
|
+
:ignore,
|
27
|
+
:raise_error,
|
28
|
+
:warn,
|
29
|
+
]
|
30
|
+
def on_circular_dependency=(new_value)
|
31
|
+
if !new_value.in?(ON_CIRCULAR_DEPENDENCY_VALUES)
|
32
|
+
raise ArgumentError, "#{new_value} is not a valid value for on_circular_dependency. Use one of #{ON_CIRCULAR_DEPENDENCY_VALUES}"
|
33
|
+
end
|
34
|
+
@on_circular_dependency = new_value
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/uses/error.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Uses
|
2
|
+
module Initializer
|
3
|
+
class BaseInitializer
|
4
|
+
def initialize(uses_method_args)
|
5
|
+
@proc = self.create_proc(uses_method_args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
@proc.()
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def create_proc(uses_method_args)
|
15
|
+
raise "subclass must implement"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative "base_initializer"
|
2
|
+
|
3
|
+
class Uses::Initializer::FromInitializers < Uses::Initializer::BaseInitializer
|
4
|
+
def create_proc(uses_method_args)
|
5
|
+
uses_method_args.uses_config.initializers.fetch(uses_method_args.klass_being_used)
|
6
|
+
rescue KeyError
|
7
|
+
raise "An initializer for #{uses_method_args.klass_being_used.name} has not been defined. #{uses_method_args.klass_with_uses.name} has set initialize: to :config_initializers, which means it's assuming some other file (e.g. in config/initializers) has called Uses.initializers to set up the initialization"
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative "base_initializer"
|
2
|
+
|
3
|
+
class Uses::Initializer::NewNoArgs < Uses::Initializer::BaseInitializer
|
4
|
+
def create_proc(uses_method_args)
|
5
|
+
initialize_method = uses_method_args.klass_being_used.instance_method(:initialize)
|
6
|
+
if !initialize_method.arity.in?([0,-1])
|
7
|
+
raise "#{uses_method_args.klass_being_used}'s initializer has required arguments, but has been used in #{uses_method_args.klass_with_uses.class} to initializer with no arguments passed to ::new. Please use initialize: with a Proc or :config_initializers to control how the instance is created"
|
8
|
+
end
|
9
|
+
->() { uses_method_args.klass_being_used.new }
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "error"
|
2
|
+
require_relative "initializer/new_no_args"
|
3
|
+
require_relative "initializer/from_initializers"
|
4
|
+
require_relative "initializer/proc_based"
|
5
|
+
|
6
|
+
module Uses
|
7
|
+
module Initializer
|
8
|
+
def self.from_args(uses_method_args)
|
9
|
+
strategy_klass(uses_method_args).new(uses_method_args)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def self.strategy_klass(uses_method_args)
|
15
|
+
case uses_method_args.initializer_strategy
|
16
|
+
when :new_no_args then NewNoArgs
|
17
|
+
when :config_initializers then FromInitializers
|
18
|
+
when Proc then ProcBased
|
19
|
+
else
|
20
|
+
raise UnknownInitializerStrategy.new(uses_method_args.initializer_strategy)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
class UnknownInitializerStrategy < Uses::Error
|
26
|
+
def initialize(strategy)
|
27
|
+
if strategy.kind_of?(Symbol)
|
28
|
+
super("initialize: received #{strategy}, which is not supported. Should be either the symbol :config_initializers, a Proc, or simply omitted")
|
29
|
+
else
|
30
|
+
super("initialize: received a #{strategy.class}, which is not supported. Should be either the symbol :config_initializers, a Proc, or simply omitted")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Uses
|
2
|
+
# Convienience methods for test to inject mocks/doubles into a class under test.
|
3
|
+
#
|
4
|
+
# An advantage of "injecting" dependencies is that you can provide alternate implementations
|
5
|
+
# for testing that simplify your tests. While Ruby doesn't strictly require that you make
|
6
|
+
# dependencies injectible, it is nice to have a bit of help in doing to so for a test.
|
7
|
+
#
|
8
|
+
# If using RSpec, use `inject_rspec_double`.
|
9
|
+
module InjectDouble
|
10
|
+
# Inject an instantiated double into subject, returing the double.
|
11
|
+
#
|
12
|
+
# subject:: the instance of the class under test where you want a double injected
|
13
|
+
# injectsion:: a hash of size 1 where the key is the class given to `uses` and
|
14
|
+
# the value is the doubled object
|
15
|
+
def inject_double(subject, injections)
|
16
|
+
if injections.size != 1
|
17
|
+
raise "expected a single key/value to inject_double, but got #{injections.size}"
|
18
|
+
end
|
19
|
+
|
20
|
+
klass = injections.first[0]
|
21
|
+
instance = injections.first[1]
|
22
|
+
|
23
|
+
subject_must_use_uses!(subject)
|
24
|
+
injected_class_must_be_class!(klass)
|
25
|
+
|
26
|
+
name = dependency_method_name!(subject, klass)
|
27
|
+
|
28
|
+
subject.__uses_dependent_instances[name] = instance
|
29
|
+
|
30
|
+
instance
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# For Rspec users, you might do:
|
35
|
+
#
|
36
|
+
# dependent_service = instance_doule(DependentService)
|
37
|
+
# allow(DependentService).to receive(:new).and_return(dependent_service)
|
38
|
+
#
|
39
|
+
# The problem is that it would be nice to know if your class under test actually uses the
|
40
|
+
# dependent service, plus it's annoying to have to write two lines of code.
|
41
|
+
#
|
42
|
+
# Instead:
|
43
|
+
#
|
44
|
+
# dependent_service = instance_double(object_under_test, DependentService)
|
45
|
+
#
|
46
|
+
# If you depend in DependentService, this will replace the real instance with yours. If you do not
|
47
|
+
# it will raise an error.
|
48
|
+
def inject_rspec_double(subject, klass)
|
49
|
+
self.inject_double(subject, klass => instance_double(klass))
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def subject_must_use_uses!(subject)
|
55
|
+
if !subject.class.respond_to?(:__uses_dependent_classes)
|
56
|
+
raise Uses::Error, "#{subject.class} does not include Uses::Method, so you cannot inject a double into it"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def injected_class_must_be_class!(klass)
|
61
|
+
if !klass.kind_of?(Class)
|
62
|
+
raise Uses::Error, "Pass the actual class, not a #{klass.class}."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def dependency_method_name!(subject, klass)
|
67
|
+
name = subject.class.__uses_dependent_classes[klass].to_s
|
68
|
+
|
69
|
+
if name.blank?
|
70
|
+
raise Uses::Error, "#{subject.class} does not depend on a #{klass}, so there is no reason to inject a mock"
|
71
|
+
end
|
72
|
+
name
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/uses/method.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
require "active_support/core_ext/string/inflections"
|
3
|
+
|
4
|
+
require_relative "config"
|
5
|
+
require_relative "method_name"
|
6
|
+
require_relative "initializer"
|
7
|
+
require_relative "uses_method_args"
|
8
|
+
require_relative "circular_dependency/analyzer"
|
9
|
+
|
10
|
+
module Uses
|
11
|
+
# Provides a very basic mechanism for dependency management between classes in your service
|
12
|
+
# layer. This is done via the method `uses`.
|
13
|
+
#
|
14
|
+
# The simplest use of this module is to create a base class for all classes in your service layer:
|
15
|
+
#
|
16
|
+
# # app/services/application_service.rb
|
17
|
+
# class ApplicationService
|
18
|
+
# include Uses::Method
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Then, all services inherit from this and have access to the uses method.
|
22
|
+
#
|
23
|
+
# Note that any class or method without RubyDoc should be treated as private/internal, and you
|
24
|
+
# should not depend on.
|
25
|
+
module Method
|
26
|
+
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
class_methods do
|
30
|
+
# Declare that the class including the Uses::Method module depends on another
|
31
|
+
# class. This will create an instance method on this class that returns a memoized
|
32
|
+
# instance of the class passed in (klass).
|
33
|
+
#
|
34
|
+
# klass:: the class of what is dependend-upon.
|
35
|
+
# as:: if given, overrides the default naming for the instance method.
|
36
|
+
# By default (when as: is omitted or set to nil), the name will
|
37
|
+
# be `klass.underscore.gsub(/\//,"_")` (see Uses::MethodName),
|
38
|
+
# so for a class named SomeClass, it would be `some_class`, however for
|
39
|
+
# a class named SomeNamespace::SomeClass, it would be `some_namespace_some_class`.
|
40
|
+
# If you set a value for `as:` that value would be used instead of this auto-generated value.
|
41
|
+
# initialize: Controls how the instance is initialized:
|
42
|
+
# :new_no_args:: create the instance with `.new` an no args. This is the default, since
|
43
|
+
# most service-layer classes should not need initializer arguments.
|
44
|
+
# :config_initializers:: Indicates that an intiailzation proc has been previously
|
45
|
+
# configured and should be used. See ::initializers above.
|
46
|
+
# a Proc:: The `Proc` is called to return the new instance. Generally you would
|
47
|
+
# only use this if your class required special initialization but is only
|
48
|
+
# used in *this* class. Keep in mind that this couples the service with
|
49
|
+
# how to iniltialize its dependent, which is not often a good thing. But
|
50
|
+
# sometimes you have to.
|
51
|
+
def uses(klass, as: nil, initialize: :new_no_args)
|
52
|
+
uses_method_args = Uses::UsesMethodArgs.new(
|
53
|
+
klass_being_used: klass,
|
54
|
+
klass_with_uses: self,
|
55
|
+
method_name_override: as,
|
56
|
+
initializer_strategy: initialize,
|
57
|
+
uses_config: Uses.config
|
58
|
+
)
|
59
|
+
|
60
|
+
name = Uses::MethodName.new(uses_method_args)
|
61
|
+
circular_dependency_analyzer = Uses::CircularDependency::Analyzer.new(uses_method_args)
|
62
|
+
initializer = Uses::Initializer.from_args(uses_method_args)
|
63
|
+
|
64
|
+
circular_dependency_analyzer.analyze!
|
65
|
+
|
66
|
+
if circular_dependency_analyzer.circular_dependency?
|
67
|
+
circular_dependency_analyzer.notify!
|
68
|
+
end
|
69
|
+
|
70
|
+
self.__uses_dependent_classes[klass] = name
|
71
|
+
|
72
|
+
define_method name.to_s do
|
73
|
+
self.__uses_dependent_instances[name.to_s] ||= initializer.()
|
74
|
+
end
|
75
|
+
private name.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
def __uses_dependent_classes
|
79
|
+
@__uses_dependent_classes ||= {}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def __uses_dependent_instances
|
84
|
+
@__uses_dependent_instances ||= {}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "invalid_method_name"
|
2
|
+
module Uses
|
3
|
+
class MethodName
|
4
|
+
|
5
|
+
def self.derive_method_name(klass)
|
6
|
+
klass.name.to_s.underscore.gsub(/\//,"_")
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(uses_method_args)
|
10
|
+
@name = if uses_method_args.method_name_override.nil?
|
11
|
+
self.class.derive_method_name(uses_method_args.klass_being_used)
|
12
|
+
else
|
13
|
+
uses_method_args.method_name_override.to_s
|
14
|
+
end
|
15
|
+
if @name !~ /^[a-z0-9_]+$/
|
16
|
+
raise Uses::InvalidMethodName.new("Cannot determine a default name for #{uses_method_args.klass_being_used} used by #{uses_method_args.klass_with_uses}. Use as: to specify the name")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def to_s
|
20
|
+
@name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Uses
|
2
|
+
class UsesMethodArgs
|
3
|
+
|
4
|
+
attr_reader :klass_being_used,
|
5
|
+
:klass_with_uses,
|
6
|
+
:method_name_override,
|
7
|
+
:initializer_strategy,
|
8
|
+
:uses_config
|
9
|
+
|
10
|
+
def initialize(klass_being_used:,
|
11
|
+
klass_with_uses:,
|
12
|
+
method_name_override:,
|
13
|
+
initializer_strategy:,
|
14
|
+
uses_config:)
|
15
|
+
|
16
|
+
@klass_being_used = klass_being_used
|
17
|
+
@klass_with_uses = klass_with_uses
|
18
|
+
@method_name_override = method_name_override
|
19
|
+
@initializer_strategy = initializer_strategy
|
20
|
+
@uses_config = uses_config
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/uses/version.rb
ADDED
data/lib/uses.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Uses
|
2
|
+
# Yields a hash of initializer, with the intention that you insert
|
3
|
+
# the initializer for your service into this hash. The key should be the class name
|
4
|
+
# that would be given to a `uses` invocation, and the value should be a proc
|
5
|
+
# that returns an instance of that class.
|
6
|
+
#
|
7
|
+
# The reason you would do this is if your service requires special setup beyond calling
|
8
|
+
# new without arguments. For example:
|
9
|
+
#
|
10
|
+
#
|
11
|
+
# require "uses"
|
12
|
+
# Uses.initializers do |initializers|
|
13
|
+
# initializers[Aws::S3::Client] = ->(*) {
|
14
|
+
# Aws::S3::Client.new(
|
15
|
+
# access_key_id: ENV["AWS_ACCESS_KEY_ID"],
|
16
|
+
# secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
|
17
|
+
# region: ENV["AWS_REGION"],
|
18
|
+
# )
|
19
|
+
# }
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # Then, in a service that uses this:
|
23
|
+
#
|
24
|
+
# class MyService
|
25
|
+
# include Uses::Method
|
26
|
+
#
|
27
|
+
# uses Aws::S3::Client, as: :s3, initialize: :config_initializers
|
28
|
+
#
|
29
|
+
# def some_method
|
30
|
+
# s3.whatever # s3 has been initialized using the Proc above
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
def self.initializers
|
34
|
+
yield(config.initializers) if block_given?
|
35
|
+
config.initializers
|
36
|
+
end
|
37
|
+
|
38
|
+
# Yields the Uses::Config instance governing this
|
39
|
+
# gem's behavior. You should call this in an intializer.
|
40
|
+
# See Uses::Config for what options exist
|
41
|
+
def self.config
|
42
|
+
@@config ||= Uses::Config.new
|
43
|
+
yield(@@config) if block_given?
|
44
|
+
@@config
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
require_relative "uses/version"
|
49
|
+
require_relative "uses/method"
|
data/uses.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "lib/uses/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "uses"
|
5
|
+
spec.version = Uses::VERSION
|
6
|
+
spec.authors = ["Dave Copeland"]
|
7
|
+
spec.email = ["davec@naildrivin5.com"]
|
8
|
+
spec.summary = %q{Declare that one classes uses an instance of another to help your code be a bit more sustainable}
|
9
|
+
spec.homepage = "https://github.com/sustainable-rails/uses"
|
10
|
+
spec.license = "Hippocratic"
|
11
|
+
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
13
|
+
|
14
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
15
|
+
spec.metadata["source_code_uri"] = "https://github.com/sustainable-rails/uses"
|
16
|
+
spec.metadata["changelog_uri"] = "https://github.com/sustainable-rails/uses/releases"
|
17
|
+
|
18
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_dependency("activesupport")
|
26
|
+
spec.add_development_dependency("rspec")
|
27
|
+
spec.add_development_dependency("rspec_junit_formatter")
|
28
|
+
spec.add_development_dependency("confidence-check")
|
29
|
+
end
|