vissen-parameterized 0.1.0
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/.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
|