kindah 0.0.1
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 +15 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +228 -0
- data/Rakefile +3 -0
- data/kindah.gemspec +22 -0
- data/lib/kindah/ast/class_methods.rb +11 -0
- data/lib/kindah/ast/class_template.rb +8 -0
- data/lib/kindah/ast/instance_methods.rb +11 -0
- data/lib/kindah/ast.rb +4 -0
- data/lib/kindah/cache.rb +15 -0
- data/lib/kindah/compiler.rb +54 -0
- data/lib/kindah/version.rb +3 -0
- data/lib/kindah.rb +23 -0
- data/spec/integration/parameterized_class_spec.rb +36 -0
- data/spec/spec_helper.rb +13 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YzkwOGY0YWQ3YTZiYjA0Yzc3MmY0NjY0MTNlMmZjOWYzMTI5MjNlYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
Zjk3MTgyZDFlMGFkNTliMzRhY2Q0MWEwYzY5YTlmZjUyM2MzZTYwMQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTZlZmI1OGZlNWQ1NjU2NmY3MzJkYzM2MmY0NDQ1MWIzMDI0NmQ0NzQ1NzE2
|
10
|
+
Nzc0MDBjZTY4MTQyYmU1ZTg2ZDU3OGYzNDUyZTAzNDlmNzc2NzA0MTQ5Y2Fi
|
11
|
+
MDM0MWMwNzBmOTY2MWVjOTEzOGM1ZjEzYTE3ZDhmMTkyYWQwYWQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzI1M2FkZTUyOWVhMjVlOWE3MzlmZDAwZDYxY2RjZTk4YTY0OGJiZDM4YjE4
|
14
|
+
YTE5YTZhZTNiYzAwZGJjYWZlNTZhY2IzY2E2NjEwZDE5NzNjZjVjOGRmNWIy
|
15
|
+
MjdhMWE2ZmVlNmNiYzM1ZmFiZDM4ODlmZjU5ZjU1Y2UzYmQ3MGY=
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
kindah
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3-p429
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Joe Fredette
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,228 @@
|
|
1
|
+
# kindah [](http://badge.fury.io/rb/kindah)[](http://travis-ci.org/jfredett/kindah)[](https://codeclimate.com/github/jfredett/kindah)[](https://coveralls.io/r/jfredett/kindah)
|
2
|
+
|
3
|
+
Kindah is an implementation of Parameterized Classes for Ruby.
|
4
|
+
|
5
|
+
Kindah is unreleased, pre-alpha software, use at your own risk.
|
6
|
+
|
7
|
+
Most of this README should work, but it's not yet well-tested, so be careful.
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
A parameterized class is a 'higher order' class, it's similar to (but definitely
|
12
|
+
not equivalent or as powerful as) a dependently-typed class. If you're familiar
|
13
|
+
with type theory (and particularly with haskell), it's analogous to a 'kind',
|
14
|
+
but one rank lower. So whereas a rank-2 type is the 'type of types' and is built
|
15
|
+
of types and other 'kinds' (ie, rank-1 and rank-2 types), these parameterized
|
16
|
+
classes occupy some of the same space as dependent types (ie, rank-1 types which
|
17
|
+
are parameterized by rank-0 types (that is, values)).
|
18
|
+
|
19
|
+
This library is not a rigorous implementation of any type system, it's merely
|
20
|
+
inspired by the concept, and built for a very specific purpose. The static
|
21
|
+
injection pattern.
|
22
|
+
|
23
|
+
### Static Injection
|
24
|
+
|
25
|
+
Static injection is a type of dependency injection which happens once, generally
|
26
|
+
at compile-time, or at interpretation/loading time for interpeted languages.
|
27
|
+
Compared with setter/constructor injection, this is more akin to setter
|
28
|
+
injection, but where the setter is promoted to the class itself. This is useful
|
29
|
+
particularly where you need multiple versions of the same class which have
|
30
|
+
different 'engines' which drive them. A motivating example is an Indexing
|
31
|
+
interface for a database. Consider
|
32
|
+
|
33
|
+
|
34
|
+
class Index
|
35
|
+
attr_reader :indexing_engine
|
36
|
+
|
37
|
+
def initialize(indexing_engine = DefaultIndexingEnging)
|
38
|
+
@indexing_engine = indexing_engine.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def insert(data)
|
42
|
+
indexing_engine.insert(data)
|
43
|
+
end
|
44
|
+
|
45
|
+
#snip
|
46
|
+
end
|
47
|
+
|
48
|
+
#later
|
49
|
+
|
50
|
+
Index.new(BTree)
|
51
|
+
|
52
|
+
Here, we use constructor injection to manage which indexing engine to use,
|
53
|
+
however, this leaks the abstraction to an inappropriate place, it should never
|
54
|
+
be possible to change the engine after it's been chosen the first time. In
|
55
|
+
particular it expresses the wrong relationship. An index does not _have a_
|
56
|
+
engine, an index, in some sense, _is it's_ engine. That is, a BTree Index _is_
|
57
|
+
a BTree, with some pleasant interface adhered to it. Similarly, a Hash Index
|
58
|
+
_is_ fundamentally a hashtable, with the _same pleasant interface_.
|
59
|
+
|
60
|
+
One method for accomplishing this type of abstraction in ruby is via modules,
|
61
|
+
but Modules ought to expose cross-cutting functionality and ought to bear no
|
62
|
+
statefullness of their own, and in the case of Index, there is a fair amount of
|
63
|
+
desire to include some statefulness. Further, an aesthetic desire exists to
|
64
|
+
invert this relationship to better express the dominant status of the _Index_
|
65
|
+
over it's _Engine_. The solution that Kindah offers looks something like this:
|
66
|
+
|
67
|
+
parameterized_class :Index do |engine|
|
68
|
+
def indexing_engine
|
69
|
+
@engine ||= engine.new
|
70
|
+
end
|
71
|
+
|
72
|
+
def insert(data)
|
73
|
+
indexing_engine.insert(data)
|
74
|
+
end
|
75
|
+
|
76
|
+
#snip
|
77
|
+
end
|
78
|
+
|
79
|
+
#later
|
80
|
+
|
81
|
+
Index(BTree).new
|
82
|
+
|
83
|
+
So, looking at that last line, you're probably thinking, "Okay, so what? You
|
84
|
+
moved the BTree bit to the left." Yes. Precisely, I've also imposed a set of
|
85
|
+
restrictions and implemented some pleasant features for talking about
|
86
|
+
`Index(BTree)` as a type in it's own right. For instance,
|
87
|
+
`Index(BTree).new.is_a? Index` will return `true`, but `Index(BTree).new.is_a?
|
88
|
+
Index(HashTable)` will return `false`. Similarly, depending on defaults provided
|
89
|
+
to the above block, `Index` will be an instantiable class.
|
90
|
+
|
91
|
+
|
92
|
+
### Other uses
|
93
|
+
|
94
|
+
In this way you can hopefully see how to use this to manage some basic
|
95
|
+
dependency injection problems, however, Kindah lends itself to other uses, one
|
96
|
+
of the chief uses is metaprogramming based on values (rather than classes).
|
97
|
+
|
98
|
+
Consider the implementation of a classic Dependent Type, the finite vector.
|
99
|
+
|
100
|
+
A Vector is a list of length `n` with `O(1)` access to any element of the list
|
101
|
+
for read or write, and at most `O(n)` memory use. A simple implementation in
|
102
|
+
ruby is to metaprogram `n` 'slots' into a class, and wrap them in an interface
|
103
|
+
so that the usual `#[]` and `#[]=` operations work as expected, with bounds
|
104
|
+
checking and the like.
|
105
|
+
|
106
|
+
An implementation follows using pure ruby and using Kindah.
|
107
|
+
|
108
|
+
#pure ruby
|
109
|
+
class Vector
|
110
|
+
attr_reader :order
|
111
|
+
|
112
|
+
def initialize(order)
|
113
|
+
@order = order
|
114
|
+
end
|
115
|
+
|
116
|
+
def [](slot)
|
117
|
+
bounds_check! slot
|
118
|
+
instance_variable_get("@slot_#{slot}")
|
119
|
+
end
|
120
|
+
|
121
|
+
def []=(slot, value)
|
122
|
+
bounds_check! slot
|
123
|
+
instance_variable_set("@slot_#{slot}", value)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def bounds_check!(value)
|
129
|
+
0 <= value && value < order
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#usage
|
134
|
+
|
135
|
+
v = Vector.new(2)
|
136
|
+
v[0] = :test_value
|
137
|
+
v[1] = :please_ignore
|
138
|
+
|
139
|
+
v[0] #=> :test_value
|
140
|
+
|
141
|
+
#with kindah
|
142
|
+
|
143
|
+
parameterized_class :Vector do |size|
|
144
|
+
def order
|
145
|
+
size
|
146
|
+
end
|
147
|
+
|
148
|
+
def [](slot)
|
149
|
+
bounds_check! slot
|
150
|
+
instance_variable_get("@slot_#{slot}")
|
151
|
+
end
|
152
|
+
|
153
|
+
def []=(slot, value)
|
154
|
+
bounds_check! slot
|
155
|
+
instance_variable_set("@slot_#{slot}", value)
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def bounds_check!(value)
|
161
|
+
0 <= value && value < order
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
v = Vector(2).new
|
166
|
+
v[0] = :test_value
|
167
|
+
v[1] = :please_ignore
|
168
|
+
|
169
|
+
v[0] #=> :test_value
|
170
|
+
|
171
|
+
So... what's the difference? It's basically the same, arguably the latter is
|
172
|
+
more complicated.
|
173
|
+
|
174
|
+
Well, there are a couple advantages beyond the aesthetic API the latter
|
175
|
+
provides. First, in the former, we have to allocate some extra storage for the
|
176
|
+
order, whereas in the latter it's hardcoded (via metaprogramming) into the class
|
177
|
+
proper. Second, imagine an implementation of dot-product, which requires the two
|
178
|
+
vectors to be of the same length. In the former, we must examine orders
|
179
|
+
directly, eg:
|
180
|
+
|
181
|
+
class Vector
|
182
|
+
def dot(other)
|
183
|
+
raise unless order == other.order
|
184
|
+
#impl
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
In the latter case, we can check the class, which is only the same if the two
|
189
|
+
instances were created via the same `Vector(n)` function, eg:
|
190
|
+
|
191
|
+
parameterized_class :Vector do |order|
|
192
|
+
def dot(other)
|
193
|
+
raise unless other.is_a?(self.class)
|
194
|
+
#impl
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
This becomes more valuable when you have a few of these parameters to throw
|
199
|
+
around, for instance, imagine a `n x m` matrix class. In pure ruby, if you want
|
200
|
+
to add two instances together, you must first ensure that it matches both width
|
201
|
+
and height, with a kindah-based parameterized class, you can simply compare that
|
202
|
+
the classes are the same. Essentially, it's poor man's type checking.
|
203
|
+
|
204
|
+
## Installation
|
205
|
+
|
206
|
+
Add this line to your application's Gemfile:
|
207
|
+
|
208
|
+
gem 'kindah'
|
209
|
+
|
210
|
+
And then execute:
|
211
|
+
|
212
|
+
$ bundle
|
213
|
+
|
214
|
+
Or install it yourself as:
|
215
|
+
|
216
|
+
$ gem install kindah
|
217
|
+
|
218
|
+
## Usage
|
219
|
+
|
220
|
+
TODO: Write usage instructions here
|
221
|
+
|
222
|
+
## Contributing
|
223
|
+
|
224
|
+
1. Fork it
|
225
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
226
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
227
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
228
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/kindah.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'kindah/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "kindah"
|
8
|
+
spec.version = Kindah::VERSION
|
9
|
+
spec.authors = ["Joe Fredette"]
|
10
|
+
spec.email = ["jfredett@gmail.com"]
|
11
|
+
spec.description = %q{Kindah is an implementation of Parameterized Classes for Ruby.}
|
12
|
+
spec.summary = %q{Kindah is an implementation of Parameterized Classes for Ruby.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "katuv"
|
22
|
+
end
|
data/lib/kindah/ast.rb
ADDED
data/lib/kindah/cache.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Kindah
|
2
|
+
class Compiler
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def initialize(ast)
|
6
|
+
@ast = ast
|
7
|
+
end
|
8
|
+
|
9
|
+
def class_methods
|
10
|
+
safe_fetch ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
def instance_methods
|
14
|
+
safe_fetch InstanceMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate [:arity, :block, :children] => :@ast
|
18
|
+
def class_name
|
19
|
+
@ast.name
|
20
|
+
end
|
21
|
+
|
22
|
+
def each_parameter
|
23
|
+
class_methods.parameters.each.with_index do |(_, name), idx|
|
24
|
+
yield name, idx if block_given?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def compile!(location = Object)
|
29
|
+
compiler = self
|
30
|
+
|
31
|
+
location.send(:define_method, compiler.class_name) do |*args|
|
32
|
+
Kindah::Cache[compiler.class_name, *args] ||= Class.new do
|
33
|
+
compiler.each_parameter do |name, idx|
|
34
|
+
define_singleton_method(name) { args[idx] }
|
35
|
+
define_method(name) { self.class.send(name) }
|
36
|
+
end
|
37
|
+
|
38
|
+
#because ruby is weird...
|
39
|
+
instance_eval &compiler.class_methods
|
40
|
+
class_eval &compiler.instance_methods
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def safe_fetch(klass)
|
50
|
+
return proc {} unless children.has_key?(klass)
|
51
|
+
children[klass].block
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/kindah.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "kindah/version"
|
2
|
+
|
3
|
+
require 'katuv'
|
4
|
+
require 'forwardable'
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
require 'kindah/ast'
|
8
|
+
require 'kindah/cache'
|
9
|
+
require 'kindah/compiler'
|
10
|
+
|
11
|
+
module Kindah
|
12
|
+
def self.class_template(name, opts={}, &block)
|
13
|
+
Kindah::ClassTemplate.new(name, opts.merge(parent: nil), &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.class_template!(name, opts={}, &block)
|
17
|
+
compile! class_template(name, opts, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.compile!(template)
|
21
|
+
Kindah::Compiler.new(template).compile!
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kindah do
|
4
|
+
before :all do
|
5
|
+
Kindah.class_template! :Test do
|
6
|
+
class_methods do |bar|
|
7
|
+
def foo_class
|
8
|
+
bar + 1
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
instance_methods do
|
13
|
+
def foo_instance
|
14
|
+
bar + 1
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@ivar = 1
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :ivar
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
subject(:test_instance) { Test(1).new }
|
27
|
+
|
28
|
+
it { should respond_to :bar }
|
29
|
+
it { should respond_to :foo_instance }
|
30
|
+
it { should respond_to :ivar }
|
31
|
+
|
32
|
+
its(:ivar) { should == 1 }
|
33
|
+
|
34
|
+
its(:class) { should respond_to :bar }
|
35
|
+
its(:class) { should respond_to :foo_class }
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'crystalline/spec'
|
2
|
+
|
3
|
+
#include helpers
|
4
|
+
Dir["./spec/helpers/*.rb"].each { |file| require file }
|
5
|
+
|
6
|
+
#include shared examples
|
7
|
+
Dir["./spec/shared/*_examples.rb"].each { |file| require file }
|
8
|
+
|
9
|
+
Coveralls.wear! if ENV['COVERALLS']
|
10
|
+
|
11
|
+
Crystalline::Spec.install!
|
12
|
+
|
13
|
+
require 'kindah'
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kindah
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joe Fredette
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: katuv
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Kindah is an implementation of Parameterized Classes for Ruby.
|
28
|
+
email:
|
29
|
+
- jfredett@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- .ruby-gemset
|
36
|
+
- .ruby-version
|
37
|
+
- .travis.yml
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE.txt
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- kindah.gemspec
|
43
|
+
- lib/kindah.rb
|
44
|
+
- lib/kindah/ast.rb
|
45
|
+
- lib/kindah/ast/class_methods.rb
|
46
|
+
- lib/kindah/ast/class_template.rb
|
47
|
+
- lib/kindah/ast/instance_methods.rb
|
48
|
+
- lib/kindah/cache.rb
|
49
|
+
- lib/kindah/compiler.rb
|
50
|
+
- lib/kindah/version.rb
|
51
|
+
- spec/integration/parameterized_class_spec.rb
|
52
|
+
- spec/spec_helper.rb
|
53
|
+
homepage: ''
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 2.0.6
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Kindah is an implementation of Parameterized Classes for Ruby.
|
77
|
+
test_files:
|
78
|
+
- spec/integration/parameterized_class_spec.rb
|
79
|
+
- spec/spec_helper.rb
|