vissen-parameterized 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +67 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +48 -0
- data/LICENSE.txt +21 -0
- data/README.md +71 -0
- data/Rakefile +27 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/vissen/parameterized/accessor.rb +22 -0
- data/lib/vissen/parameterized/conditional.rb +61 -0
- data/lib/vissen/parameterized/dsl.rb +103 -0
- data/lib/vissen/parameterized/error.rb +10 -0
- data/lib/vissen/parameterized/global_scope.rb +49 -0
- data/lib/vissen/parameterized/graph.rb +34 -0
- data/lib/vissen/parameterized/parameter.rb +107 -0
- data/lib/vissen/parameterized/scope.rb +92 -0
- data/lib/vissen/parameterized/scope_error.rb +9 -0
- data/lib/vissen/parameterized/value/bool.rb +27 -0
- data/lib/vissen/parameterized/value/int.rb +30 -0
- data/lib/vissen/parameterized/value/real.rb +30 -0
- data/lib/vissen/parameterized/value/vec.rb +56 -0
- data/lib/vissen/parameterized/value.rb +112 -0
- data/lib/vissen/parameterized/version.rb +10 -0
- data/lib/vissen/parameterized.rb +201 -0
- data/vissen-parameterized.gemspec +39 -0
- metadata +158 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vissen
|
4
|
+
module Parameterized
|
5
|
+
# The scope exists to protect parameterized objects from being bound to
|
6
|
+
# parameters with a different lifetime than their own.
|
7
|
+
#
|
8
|
+
# Each scope is bound to a `Conditional` and as long as it, as well as the
|
9
|
+
# conditionals of all the parents return false, the scope is considered to
|
10
|
+
# be alive.
|
11
|
+
#
|
12
|
+
# By checking that one scope is included in another, it is possible to
|
13
|
+
# guarantee that values belonging to the first scope are safe to use.
|
14
|
+
class Scope
|
15
|
+
# @return [Scope] the parent of this scope.
|
16
|
+
attr_reader :parent
|
17
|
+
|
18
|
+
# A scope is considered dead once its conditional returns true, or if the
|
19
|
+
# parent scope is also dead.
|
20
|
+
#
|
21
|
+
# @return [true] if the conditional is met.
|
22
|
+
# @return [false] otherwise.
|
23
|
+
def dead?
|
24
|
+
@conditional.met? || parent.dead?
|
25
|
+
end
|
26
|
+
|
27
|
+
# The inverse of `#dead?`
|
28
|
+
#
|
29
|
+
# @see dead?
|
30
|
+
#
|
31
|
+
# @return [false] if the conditional is met.
|
32
|
+
# @return [true] otherwise.
|
33
|
+
def alive?
|
34
|
+
!dead?
|
35
|
+
end
|
36
|
+
|
37
|
+
# Forces the conditional to return true, irregardless of its actual state.
|
38
|
+
#
|
39
|
+
# @return [nil]
|
40
|
+
def kill!
|
41
|
+
@conditional.force!
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks if the given object is included, either in this scope or in any
|
45
|
+
# of the parent scopes.
|
46
|
+
#
|
47
|
+
# @param obj [#scope] the object to scope check.
|
48
|
+
# @return [true] if the object either shares this scope or a parent scope.
|
49
|
+
# @return [false] otherwise.
|
50
|
+
def include?(obj)
|
51
|
+
include_scope? obj.scope
|
52
|
+
end
|
53
|
+
|
54
|
+
alias === include?
|
55
|
+
|
56
|
+
# Creates a new scope that is a direct descendent of this one.
|
57
|
+
#
|
58
|
+
# @param conditional [Conditional] the conditional to use for the new
|
59
|
+
# scope.
|
60
|
+
# @return [Scope] a new child scope.
|
61
|
+
def create_scope(conditional)
|
62
|
+
Scope.new self, conditional
|
63
|
+
end
|
64
|
+
|
65
|
+
# Checks if the given scope is included in the scope hierarchy of this
|
66
|
+
# one.
|
67
|
+
#
|
68
|
+
# @param other [Scope, Object] the scope to check.
|
69
|
+
# @return [true] if the given scope is equal to this one, or one of the
|
70
|
+
# parents.
|
71
|
+
def include_scope?(other)
|
72
|
+
equal?(other) || @parent.include_scope?(other)
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
# Creates a new scope. This method is protected to avoid erroneous parent
|
78
|
+
# structures and new top level scopes should instead be created using
|
79
|
+
# `GlobalScope.instance.create_scope`.
|
80
|
+
#
|
81
|
+
# @raise [TypeError] if the conditional does not respond to `#met?`.
|
82
|
+
# @raise [ScopeError] if the conditional is out of scope.
|
83
|
+
def initialize(parent, conditional)
|
84
|
+
raise TypeError unless conditional.respond_to? :met?
|
85
|
+
@parent = parent
|
86
|
+
|
87
|
+
raise ScopeError unless include? conditional
|
88
|
+
@conditional = conditional
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vissen
|
4
|
+
module Parameterized
|
5
|
+
module Value
|
6
|
+
# Bool values are stored as booleans internally.
|
7
|
+
#
|
8
|
+
# === Usage
|
9
|
+
#
|
10
|
+
# bool = Bool.new true
|
11
|
+
# bool.value # => true
|
12
|
+
#
|
13
|
+
class Bool
|
14
|
+
include Value
|
15
|
+
|
16
|
+
# @return [true, false] see Value
|
17
|
+
DEFAULT = false
|
18
|
+
|
19
|
+
# @param new_value [Object] the new value.
|
20
|
+
# @return see Value#write
|
21
|
+
def write(new_value)
|
22
|
+
super new_value ? true : false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vissen
|
4
|
+
module Parameterized
|
5
|
+
module Value
|
6
|
+
# Int values are stored as Fixnums internally.
|
7
|
+
#
|
8
|
+
# === Usage
|
9
|
+
#
|
10
|
+
# int = Int.new 42
|
11
|
+
# int.value # => 42
|
12
|
+
#
|
13
|
+
class Int
|
14
|
+
include Value
|
15
|
+
|
16
|
+
# @return [Fixnum] see Value
|
17
|
+
DEFAULT = 0
|
18
|
+
|
19
|
+
# @raise [TypeError] if the given object cannot be coerced into an
|
20
|
+
# integer.
|
21
|
+
#
|
22
|
+
# @param new_value [#to_i] the new value.
|
23
|
+
# @return see Value#write
|
24
|
+
def write(new_value)
|
25
|
+
super Integer(new_value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vissen
|
4
|
+
module Parameterized
|
5
|
+
module Value
|
6
|
+
# Real values are stored as floats internally.
|
7
|
+
#
|
8
|
+
# === Usage
|
9
|
+
#
|
10
|
+
# real = Real.new 42
|
11
|
+
# real.value # => 42.0
|
12
|
+
#
|
13
|
+
class Real
|
14
|
+
include Value
|
15
|
+
|
16
|
+
# @return [Float] see Value
|
17
|
+
DEFAULT = 0.0
|
18
|
+
|
19
|
+
# @raise [TypeError] if the given object cannot be coerced into a
|
20
|
+
# float.
|
21
|
+
#
|
22
|
+
# @param new_value [#to_f] the new value.
|
23
|
+
# @return see Value#write
|
24
|
+
def write(new_value)
|
25
|
+
super Float(new_value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vissen
|
4
|
+
module Parameterized
|
5
|
+
module Value
|
6
|
+
# Vector type values are stored internally as arrays of floats.
|
7
|
+
#
|
8
|
+
# === Usage
|
9
|
+
#
|
10
|
+
# vec = Vec[1, 0.2]
|
11
|
+
# vec.value # => [1.0, 0.2]
|
12
|
+
#
|
13
|
+
class Vec
|
14
|
+
include Value
|
15
|
+
|
16
|
+
# @return [Array<Float>] the default value that will be used when `.new`
|
17
|
+
# is called without arguments, or with nil.
|
18
|
+
DEFAULT = [0.0, 0.0].freeze
|
19
|
+
|
20
|
+
# @param initial_value [Array<#to_f>] the initial value to use.
|
21
|
+
def initialize(initial_value = nil)
|
22
|
+
@value = DEFAULT.dup
|
23
|
+
taint!
|
24
|
+
|
25
|
+
write initial_value if initial_value
|
26
|
+
end
|
27
|
+
|
28
|
+
# @raise [TypeError] if the given value does not respond to `#[]`.
|
29
|
+
# @raise [TypeError] if the elements of the given value does not cannot
|
30
|
+
# be coerced into floats.
|
31
|
+
#
|
32
|
+
# @param new_value [Array<#to_f>] the new values to write.
|
33
|
+
# @return [nil]
|
34
|
+
def write(new_value)
|
35
|
+
return if @value == new_value
|
36
|
+
|
37
|
+
@value[0] = Float(new_value[0])
|
38
|
+
@value[1] = Float(new_value[1])
|
39
|
+
taint!
|
40
|
+
nil
|
41
|
+
rescue NoMethodError
|
42
|
+
raise TypeError, 'The given object must support #[]'
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
# @param a [#to_f] the first vector component.
|
47
|
+
# @param b [#to_f] the second vector component.
|
48
|
+
# @return [Vec] a new Vec instance.
|
49
|
+
def [](a, b)
|
50
|
+
new [a, b]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vissen
|
4
|
+
module Parameterized
|
5
|
+
# The Value module implements the basic functionallity of a value type.
|
6
|
+
# Class implementations are encouraged to override #write to provide type
|
7
|
+
# checking or coercion.
|
8
|
+
#
|
9
|
+
# === Usage
|
10
|
+
# The following example implements an integer type by calling #to_i on
|
11
|
+
# objects before they are written.
|
12
|
+
#
|
13
|
+
# class Int
|
14
|
+
# include Value
|
15
|
+
# DEFAULT = 0
|
16
|
+
#
|
17
|
+
# def write(new_value)
|
18
|
+
# super new_value.to_i
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
module Value
|
23
|
+
# @return [Object] the internal value object.
|
24
|
+
attr_reader :value
|
25
|
+
|
26
|
+
# @return [Object] the default value that will be used when `.new` is
|
27
|
+
# called without arguments, or with nil.
|
28
|
+
DEFAULT = nil
|
29
|
+
|
30
|
+
# @param value [Object] the initial value to use. Ignored if nil.
|
31
|
+
def initialize(value = nil)
|
32
|
+
@value = nil
|
33
|
+
@tainted = true
|
34
|
+
|
35
|
+
write(value.nil? ? self.class::DEFAULT : value)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Updates the internally stored value. The object will be marked as
|
39
|
+
# tainted if the new value differs from the previous.
|
40
|
+
#
|
41
|
+
# @param new_value [Object] the new value to write.
|
42
|
+
# @return [true] if the value was changed.
|
43
|
+
# @return [false] otherwise.
|
44
|
+
def write(new_value)
|
45
|
+
return false if new_value == @value
|
46
|
+
@value = new_value
|
47
|
+
taint!
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [true] if the value has been written to since the last call to
|
52
|
+
# `#untaint!`.
|
53
|
+
# @return [false] otherwise.
|
54
|
+
def tainted?
|
55
|
+
@tainted
|
56
|
+
end
|
57
|
+
|
58
|
+
# Marks the value as untainted.
|
59
|
+
#
|
60
|
+
# @return [false]
|
61
|
+
def untaint!
|
62
|
+
@tainted = false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Values are always considered part of the global scope.
|
66
|
+
#
|
67
|
+
# @return [Scope] the scope of the value.
|
68
|
+
def scope
|
69
|
+
GlobalScope.instance
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Array<Module>] an array of the modules and classes that include
|
73
|
+
# the `Value` module.
|
74
|
+
def self.types
|
75
|
+
@types
|
76
|
+
end
|
77
|
+
|
78
|
+
# Converts a class name to a string.
|
79
|
+
#
|
80
|
+
# Vissen::Parameterized::Value::Real -> "real"
|
81
|
+
#
|
82
|
+
# @param klass [Class] the class to canonicalize.
|
83
|
+
# @return [String] a string version of the class name.
|
84
|
+
def self.canonicalize(klass)
|
85
|
+
klass.name
|
86
|
+
.split('::').last
|
87
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
88
|
+
.downcase
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [String] the value formated as a string, with an appended '*' if
|
92
|
+
# the value is tainted.
|
93
|
+
def to_s
|
94
|
+
base = @value.to_s
|
95
|
+
tainted? ? base + '*' : base
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def taint!
|
101
|
+
@tainted = true
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param mod [Module]
|
105
|
+
def self.included(mod)
|
106
|
+
(@types ||= []) << mod
|
107
|
+
end
|
108
|
+
|
109
|
+
private_class_method :included
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
require 'vissen/parameterized/version'
|
7
|
+
require 'vissen/parameterized/error'
|
8
|
+
require 'vissen/parameterized/scope_error'
|
9
|
+
require 'vissen/parameterized/accessor'
|
10
|
+
require 'vissen/parameterized/scope'
|
11
|
+
require 'vissen/parameterized/global_scope'
|
12
|
+
require 'vissen/parameterized/value'
|
13
|
+
require 'vissen/parameterized/value/bool'
|
14
|
+
require 'vissen/parameterized/value/int'
|
15
|
+
require 'vissen/parameterized/value/real'
|
16
|
+
require 'vissen/parameterized/value/vec'
|
17
|
+
require 'vissen/parameterized/parameter'
|
18
|
+
require 'vissen/parameterized/dsl'
|
19
|
+
require 'vissen/parameterized/graph'
|
20
|
+
|
21
|
+
module Vissen
|
22
|
+
# A parameterized object should have
|
23
|
+
# - a set of parameters,
|
24
|
+
# - a (possibly expensive) function that transforms the parameters to an
|
25
|
+
# output, and
|
26
|
+
# - an output value.
|
27
|
+
module Parameterized
|
28
|
+
extend Forwardable
|
29
|
+
|
30
|
+
INSPECT_FORMAT = '#<%<name>s:0x%016<object_id>x (%<params>s) -> %<type>s>'
|
31
|
+
private_constant :INSPECT_FORMAT
|
32
|
+
|
33
|
+
# @!method value
|
34
|
+
# @return [Object] the output value.
|
35
|
+
def_delegators :@_value, :value, :to_s
|
36
|
+
|
37
|
+
# @!method returns_a?(value_klass)
|
38
|
+
# Checks if the parameterized object returns a value of the given value
|
39
|
+
# class.
|
40
|
+
#
|
41
|
+
# @param value_klass [Class] the class to test.
|
42
|
+
# @return [true] if the output value is of the given class.
|
43
|
+
# @return [false] otherwise.
|
44
|
+
def_delegator :@_value, :is_a?, :returns_a?
|
45
|
+
|
46
|
+
# Forwards all arguments to super.
|
47
|
+
#
|
48
|
+
# @param args [Array<Object>] the arguments to forward to super.
|
49
|
+
# @param parameters [Hash<Symbol, Parameter>] the input parameters.
|
50
|
+
# @param output [Value] the output value object.
|
51
|
+
# @param scope [Scope] the scope of the object.
|
52
|
+
# @param setup [Hash<Symbol, Object>] the initial setup.
|
53
|
+
def initialize(*args,
|
54
|
+
parameters:,
|
55
|
+
output:,
|
56
|
+
scope: GlobalScope.instance,
|
57
|
+
setup: {})
|
58
|
+
@_accessor = Accessor.new parameters
|
59
|
+
@_params = parameters
|
60
|
+
@_scope = scope
|
61
|
+
@_value = output
|
62
|
+
@_checked = false
|
63
|
+
|
64
|
+
load_initial setup
|
65
|
+
|
66
|
+
super(*args)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @raise [NotImplementedError] if not implemented by descendent.
|
70
|
+
#
|
71
|
+
# @param _parameters [Accessor] the parameters of the parameterized object.
|
72
|
+
# @return [Object] an object compatible with the output value type should be
|
73
|
+
# returned.
|
74
|
+
def call(_parameters)
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
|
78
|
+
# Marks the output value and all input parameters as untainted.
|
79
|
+
#
|
80
|
+
# @return [false]
|
81
|
+
def untaint!
|
82
|
+
# ASUMPTION: if the value has not been taint checked
|
83
|
+
# there should be no untainted values in
|
84
|
+
# this part of the graph. This does not
|
85
|
+
# hold initially.
|
86
|
+
return unless @_checked
|
87
|
+
@_checked = false
|
88
|
+
|
89
|
+
@_params.each { |_, param| param.untaint! }
|
90
|
+
@_value.untaint!
|
91
|
+
end
|
92
|
+
|
93
|
+
# Checks if the output value of the parameterized object has changed. If any
|
94
|
+
# of the input parameters have changed since last calling `#untaint!` the
|
95
|
+
# `#call` method will be evaluated in order to determine the state of the
|
96
|
+
# output value.
|
97
|
+
#
|
98
|
+
# Note that `#call` is only evaluated once after the object has been
|
99
|
+
# untainted. Subsequent calls to `#tainted?` will refer to the result of the
|
100
|
+
# first operation.
|
101
|
+
#
|
102
|
+
# @return [true] if the output value has changed since last calling
|
103
|
+
# `#untaint!`.
|
104
|
+
# @return [false] otherwise.
|
105
|
+
def tainted?
|
106
|
+
return @_value.tainted? if @_checked
|
107
|
+
@_checked = true
|
108
|
+
|
109
|
+
params_tainted =
|
110
|
+
@_params.reduce(false) do |a, (_, param)|
|
111
|
+
param.tainted? || a
|
112
|
+
end
|
113
|
+
|
114
|
+
return false unless params_tainted
|
115
|
+
|
116
|
+
@_value.write call(@_accessor)
|
117
|
+
end
|
118
|
+
|
119
|
+
# @return [true] if the parameterized object has the given parameter.
|
120
|
+
# @return [false] otherwise.
|
121
|
+
def parameter?(key)
|
122
|
+
@_params.key? key
|
123
|
+
end
|
124
|
+
|
125
|
+
# Binds a parameter to a target value.
|
126
|
+
#
|
127
|
+
# @see Parameter#bind
|
128
|
+
# @raise [KeyError] if the parameter is not found.
|
129
|
+
# @raise [ScopeError] if the parameter is out of scope.
|
130
|
+
#
|
131
|
+
# @param param [Symbol] the parameter to bind.
|
132
|
+
# @param target [#value] the value object to bind to.
|
133
|
+
# @return [Parameter] the parameter that was bound.
|
134
|
+
def bind(param, target)
|
135
|
+
raise ScopeError unless scope.include? target
|
136
|
+
@_params.fetch(param).bind target
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sets the constant value of a parameter.
|
140
|
+
#
|
141
|
+
# @see Parameter#set
|
142
|
+
# @raise [KeyError] if the parameter is not found.
|
143
|
+
#
|
144
|
+
# @param param [Symbol] the parameter to bind.
|
145
|
+
# @param value [Object] the value to set.
|
146
|
+
# @return [Parameter] the parameter that was set.
|
147
|
+
def set(param, value)
|
148
|
+
@_params.fetch(param).set value
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [Accessor] a proxy object that provides access to parameters via
|
152
|
+
# method calls instead of hash lookups.
|
153
|
+
def parameters
|
154
|
+
@_accessor
|
155
|
+
end
|
156
|
+
|
157
|
+
alias params parameters
|
158
|
+
|
159
|
+
# @return [Scope] the scope to which the parameterized object belongs.
|
160
|
+
def scope
|
161
|
+
@_scope
|
162
|
+
end
|
163
|
+
|
164
|
+
# Produces a readable string representation of the parameterized object.
|
165
|
+
#
|
166
|
+
# @return [String] a string representation.
|
167
|
+
def inspect
|
168
|
+
format INSPECT_FORMAT, name: self.class.name,
|
169
|
+
object_id: object_id,
|
170
|
+
params: params_with_types,
|
171
|
+
type: Value.canonicalize(@_value.class)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Iterates over the parameterized objects currently bound to the parameters.
|
175
|
+
#
|
176
|
+
# @return [Enumerable] if no block is given.
|
177
|
+
def each_parameterized
|
178
|
+
return to_enum(__callee__) unless block_given?
|
179
|
+
@_params.each do |_, param|
|
180
|
+
next if param.constant?
|
181
|
+
target = param.target
|
182
|
+
yield target if target.is_a? Parameterized
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def load_initial(setup)
|
189
|
+
setup.each do |key, value|
|
190
|
+
@_params.fetch(key)
|
191
|
+
.send(value.respond_to?(:value) ? :bind : :set, value)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def params_with_types
|
196
|
+
@_params.map { |k, v| "#{k}:#{Value.canonicalize(v.type)}" }.join(', ')
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
require 'vissen/parameterized/conditional'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'vissen/parameterized/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'vissen-parameterized'
|
10
|
+
spec.version = Vissen::Parameterized::VERSION
|
11
|
+
spec.authors = ['Sebastian Lindberg']
|
12
|
+
spec.email = ['seb.lindberg@gmail.com']
|
13
|
+
|
14
|
+
spec.summary = 'Parameterized creates a dependency graph for pure ' \
|
15
|
+
'functions.'
|
16
|
+
spec.description = 'This utility library gives objects the ability to ' \
|
17
|
+
'declare input dependencies, a transformation of ' \
|
18
|
+
'those inputs and an output value. Forcing ' \
|
19
|
+
'dependencies to be acyclic, the library can always ' \
|
20
|
+
'find a valid update order of all the transformations.'
|
21
|
+
spec.homepage = 'https://github.com/midi-visualizer/vissen-parameterized'
|
22
|
+
spec.license = 'MIT'
|
23
|
+
|
24
|
+
spec.metadata['yard.run'] = 'yri'
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
f.match(%r{^(test|spec|features)/})
|
28
|
+
end
|
29
|
+
spec.bindir = 'exe'
|
30
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
34
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
35
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.52'
|
37
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
38
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
39
|
+
end
|