adherence 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/Gemfile.lock +24 -0
- data/README.md +141 -0
- data/adherence.gemspec +13 -0
- data/lib/adherence.rb +12 -0
- data/lib/adherence/class.rb +38 -0
- data/lib/adherence/module.rb +63 -0
- data/spec/adherence_class_spec.rb +104 -0
- data/spec/adherence_module_spec.rb +133 -0
- metadata +73 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
adherence (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.3)
|
10
|
+
rspec (2.11.0)
|
11
|
+
rspec-core (~> 2.11.0)
|
12
|
+
rspec-expectations (~> 2.11.0)
|
13
|
+
rspec-mocks (~> 2.11.0)
|
14
|
+
rspec-core (2.11.1)
|
15
|
+
rspec-expectations (2.11.2)
|
16
|
+
diff-lcs (~> 1.1.3)
|
17
|
+
rspec-mocks (2.11.2)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
adherence!
|
24
|
+
rspec (~> 2.11.0)
|
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# Adherence
|
2
|
+
|
3
|
+
Adherence adds simple interface-like behavior to Ruby.
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
A common practice in object oriented programming languages is to declare abstract behavior in a certain type whose actual behavior must be defined by types implementing the abstract type.
|
8
|
+
|
9
|
+
In Java, for example, this is abstract behavior may be defined in an abstract class or an interface. In many dynamically types languages, like Ruby, duck typing makes these abstract types unneccessary. However, it is common to see in Ruby programs the following abstract-like method pattern:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Validator
|
13
|
+
def validate(record)
|
14
|
+
raise NotImplementedError, "Subclasses must implement a validate(record) method."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
Adherence provides a simple means of declaring abstract behavior in Ruby modules and enforcing their complete implementation in any class adhereing to this module.
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
A class may adhere to any number of modules by use of the adheres_to method.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
module ElectronicDevice
|
27
|
+
def on() end
|
28
|
+
|
29
|
+
def off() end
|
30
|
+
|
31
|
+
def self.compatible?(device1, device2) end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Calculator
|
35
|
+
def add(x1, x2) end
|
36
|
+
|
37
|
+
def subtract(x1, x2) end
|
38
|
+
|
39
|
+
def multiply(x1, x2) end
|
40
|
+
|
41
|
+
def divide(x1, x2) end
|
42
|
+
end
|
43
|
+
|
44
|
+
class TexasInstruments
|
45
|
+
def on
|
46
|
+
@power = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def off
|
50
|
+
@power = false
|
51
|
+
end
|
52
|
+
|
53
|
+
def add(x1, x2)
|
54
|
+
x1 + x2
|
55
|
+
end
|
56
|
+
|
57
|
+
def subtract(x1, x2)
|
58
|
+
x1 - x2
|
59
|
+
end
|
60
|
+
|
61
|
+
def multiply(x1, x2)
|
62
|
+
x1 * x2
|
63
|
+
end
|
64
|
+
|
65
|
+
def divide(x1, x2)
|
66
|
+
x1 / x2
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.compatible?(device1, device2)
|
70
|
+
device1.respond_to?(:add) && device2.respond_to?(:add)
|
71
|
+
end
|
72
|
+
|
73
|
+
adheres_to ElectronicDevice, Calculator
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
A class must define all instance and class methods of all visibilities defined in each module passed to adheres_to or an error is raised. Not only must all methods be defined, but their method signitures must match those of the specified module(s). Failure to implement all methods will result in a NotImplementedError when the class is loaded. Failure to incorrectly declare a message signature will result in a Adherence::NotAdheredError when the class is loaded. Because the methods defined in the class must be inspected, adheres_to must be called after the methods are defined in the class.
|
78
|
+
|
79
|
+
Similarly, a module may adhere to other modules:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
module ScientificCalculator
|
83
|
+
adhere_to Calculator
|
84
|
+
|
85
|
+
def factorial(n) end
|
86
|
+
|
87
|
+
def power(base, exponent) end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
In this case, the module is not expected to redefine the methods defined in the modules passed to adheres_to, rather these methods will be redefined within the calling module to raise an error when invoked directly. Thus the module ScientificCalculator in the example above will be redefined to look like this:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
module ScientificCalculator
|
95
|
+
def on
|
96
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
97
|
+
end
|
98
|
+
|
99
|
+
def off
|
100
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
101
|
+
end
|
102
|
+
|
103
|
+
def add(x1, x2)
|
104
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
105
|
+
end
|
106
|
+
|
107
|
+
def subtract(x1, x2)
|
108
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
109
|
+
end
|
110
|
+
|
111
|
+
def multiply(x1, x2)
|
112
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
113
|
+
end
|
114
|
+
|
115
|
+
def divide(x1, x2)
|
116
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.compatible?(device1, device2)
|
120
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
121
|
+
end
|
122
|
+
|
123
|
+
def factorial(n) end
|
124
|
+
|
125
|
+
def power(base, exponent) end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
So if any class that includes or extends ScientificCalculator and does not override these methods, a NotImplementedError would be raised if any of them were called.
|
130
|
+
|
131
|
+
## Requirements
|
132
|
+
|
133
|
+
Due to some of the methods used to inspect method signatures, Adherence is only compatible with Ruby version >= 1.9.2-p180.
|
134
|
+
|
135
|
+
## Installation
|
136
|
+
|
137
|
+
gem install adherence
|
138
|
+
|
139
|
+
## License
|
140
|
+
|
141
|
+
Adherence is released under the [MIT license](http://www.opensource.org/licenses/MIT). Copyright (c) 2012 Mike Bradford.
|
data/adherence.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "adherence"
|
3
|
+
spec.version = "0.1.0"
|
4
|
+
spec.date = "2012-08-30"
|
5
|
+
spec.summary = "Adds simple interface-like behavior to Ruby"
|
6
|
+
spec.authors = ["Mike Bradford"]
|
7
|
+
spec.email = "mbradford@47primes.com"
|
8
|
+
spec.files = Dir["#{File.dirname(__FILE__)}/**/*"]
|
9
|
+
spec.test_files = Dir.glob("spec/*_spec.rb")
|
10
|
+
spec.homepage = "http://github.com/47primes/adherence"
|
11
|
+
|
12
|
+
spec.add_development_dependency "rspec", "~> 2.11.0"
|
13
|
+
end
|
data/lib/adherence.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Adherence
|
2
|
+
class NotAdheredError < NotImplementedError; end
|
3
|
+
module Class
|
4
|
+
|
5
|
+
def adheres_to(*args)
|
6
|
+
args.each {|mod| adheres_to_module mod}
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def adheres_to_module(mod)
|
12
|
+
raise ArgumentError, "Module expected" unless mod.class.to_s == "Module"
|
13
|
+
|
14
|
+
(mod.instance_methods(false) + mod.private_instance_methods(false)).each do |method|
|
15
|
+
if !(instance_methods + private_instance_methods).include?(method)
|
16
|
+
raise NotImplementedError, "#{self.class} must define #{method}"
|
17
|
+
end
|
18
|
+
if !equal? instance_method(method), mod.instance_method(method)
|
19
|
+
raise NotAdheredError, "Signature does not match #{mod}##{method}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module_class_methods = mod.singleton_class.instance_methods(false) + mod.singleton_class.private_instance_methods(false)
|
24
|
+
module_class_methods.each do |method|
|
25
|
+
if !(singleton_class.instance_methods + singleton_class.private_instance_methods).include?(method)
|
26
|
+
raise NotImplementedError, "#{self.class} must define self.#{method}"
|
27
|
+
end
|
28
|
+
if !equal? singleton_class.instance_method(method), mod.singleton_class.instance_method(method)
|
29
|
+
raise NotAdheredError, "Signature does not match #{mod}.#{method}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def equal?(method1, method2)
|
35
|
+
method1.name == method2.name && method1.parameters == method2.parameters ? true : false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Adherence
|
2
|
+
class ModuleTerminatedError < StandardError; end
|
3
|
+
module Module
|
4
|
+
|
5
|
+
def adheres_to(*args)
|
6
|
+
args.each { |mod| adheres_to_module(mod) }
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def adheres_to_module(mod)
|
12
|
+
raise ArgumentError, "Module expected" unless mod.class.to_s == "Module"
|
13
|
+
|
14
|
+
mod.public_instance_methods(false).each do |method|
|
15
|
+
add_method mod.instance_method(method)
|
16
|
+
end
|
17
|
+
|
18
|
+
mod.protected_instance_methods(false).each do |method|
|
19
|
+
add_method mod.instance_method(method)
|
20
|
+
end
|
21
|
+
protected *mod.protected_instance_methods(false)
|
22
|
+
|
23
|
+
mod.private_instance_methods(false).each do |method|
|
24
|
+
add_method mod.instance_method(method)
|
25
|
+
end
|
26
|
+
private *mod.private_instance_methods(false)
|
27
|
+
|
28
|
+
mod.singleton_class.public_instance_methods(false).each do |method|
|
29
|
+
add_method mod.singleton_class.instance_method(method), true
|
30
|
+
end
|
31
|
+
|
32
|
+
mod.singleton_class.protected_instance_methods(false).each do |method|
|
33
|
+
add_method mod.singleton_class.instance_method(method), true
|
34
|
+
end
|
35
|
+
singleton_class.send :protected, *mod.singleton_class.protected_instance_methods(false)
|
36
|
+
|
37
|
+
mod.singleton_class.private_instance_methods(false).each do |method|
|
38
|
+
add_method mod.singleton_class.instance_method(method), true
|
39
|
+
end
|
40
|
+
private_class_method *mod.singleton_class.private_instance_methods(false)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_method(method, singleton_method=false)
|
44
|
+
name = method.name
|
45
|
+
params = method.parameters.reduce([]) do |memo, word|
|
46
|
+
arity, param = word
|
47
|
+
case arity
|
48
|
+
when :req then memo << "#{param}"
|
49
|
+
when :opt then memo << "#{param}=nil"
|
50
|
+
when :block then memo << "&#{param}"
|
51
|
+
when :rest then memo << "*#{param}"
|
52
|
+
end
|
53
|
+
end.join(", ")
|
54
|
+
|
55
|
+
module_eval <<-DEF
|
56
|
+
def #{"self." if singleton_method}#{name}(#{params})
|
57
|
+
raise NotImplementedError, "This method must be defined in the calling class."
|
58
|
+
end
|
59
|
+
DEF
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "adherence"
|
2
|
+
|
3
|
+
module Animal
|
4
|
+
def speak() end
|
5
|
+
|
6
|
+
def move(feet) end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def life_expectancy() end
|
11
|
+
|
12
|
+
class <<self
|
13
|
+
def build(name, &block) end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Object, "adheres_to" do
|
18
|
+
|
19
|
+
before do
|
20
|
+
class Duck
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
def initialize(name)
|
24
|
+
@name = name
|
25
|
+
end
|
26
|
+
|
27
|
+
def speak
|
28
|
+
"quack"
|
29
|
+
end
|
30
|
+
|
31
|
+
def move(feet)
|
32
|
+
"waddle #{feet} feet"
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def life_expectancy
|
38
|
+
10
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.build(name, &block)
|
42
|
+
Duck.new(name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should succeed if the object has defined all behavior from the module" do
|
48
|
+
expect do
|
49
|
+
class Duck
|
50
|
+
adheres_to Animal
|
51
|
+
end
|
52
|
+
end.to_not raise_error
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise an error if argument is not a module" do
|
56
|
+
expect do
|
57
|
+
class Duck
|
58
|
+
adheres_to Class.new
|
59
|
+
end
|
60
|
+
end.to raise_error(ArgumentError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should raise an error if all methods are not implemented" do
|
64
|
+
Duck.send(:remove_method, :speak)
|
65
|
+
|
66
|
+
expect do
|
67
|
+
class Duck
|
68
|
+
adheres_to Animal
|
69
|
+
end
|
70
|
+
end.to raise_error(NotImplementedError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should raise an error if all private methods are not implemented" do
|
74
|
+
Duck.send(:remove_method, :life_expectancy)
|
75
|
+
|
76
|
+
expect do
|
77
|
+
class Duck
|
78
|
+
adheres_to Animal
|
79
|
+
end
|
80
|
+
end.to raise_error(NotImplementedError)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should raise an error if all class methods are not implemented" do
|
84
|
+
Duck.singleton_class.send(:remove_method, :build)
|
85
|
+
|
86
|
+
expect { Duck.adheres_to(Animal) }.to raise_error(NotImplementedError)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should raise an error if methods are implemented with an invalid signature" do
|
90
|
+
Duck.send(:remove_method, :move)
|
91
|
+
Duck.class_eval do
|
92
|
+
def move(distance)
|
93
|
+
"waddle #{distance} feet"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
expect do
|
98
|
+
class Duck
|
99
|
+
adheres_to Animal
|
100
|
+
end
|
101
|
+
end.to raise_error(Adherence::NotAdheredError)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require "adherence"
|
2
|
+
|
3
|
+
module Vehicle
|
4
|
+
def initialize(make, model) end
|
5
|
+
|
6
|
+
def start() end
|
7
|
+
|
8
|
+
def stop() end
|
9
|
+
|
10
|
+
def accellerate(speed) end
|
11
|
+
|
12
|
+
def turn(orientation, speed=5, *args) end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def repair(area, &block) end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
class <<self
|
20
|
+
def build(*args, &block) end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def run() end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def helper(object) end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Watercraft
|
34
|
+
adheres_to Vehicle, Vehicle::ClassMethods
|
35
|
+
|
36
|
+
def dock() end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Module, "adheres_to" do
|
40
|
+
it "should raise an error if argument is not a module" do
|
41
|
+
expect { Module.new { adheres_to(Class.new())} }.to raise_error(ArgumentError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should define public instance methods based on module" do
|
45
|
+
Watercraft.instance_method(:start).parameters.should == []
|
46
|
+
Watercraft.instance_method(:stop).parameters.should == []
|
47
|
+
Watercraft.instance_method(:accellerate).parameters.should == [[:req, :speed]]
|
48
|
+
Watercraft.instance_method(:turn).parameters.should == [[:req, :orientation], [:opt, :speed], [:rest, :args]]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should define protected instance methods based on module" do
|
52
|
+
Watercraft.protected_method_defined?(:repair).should be_true
|
53
|
+
Watercraft.instance_method(:repair).parameters.should == [[:req, :area], [:block, :block]]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should define private instance methods based on module" do
|
57
|
+
Watercraft.private_method_defined?(:initialize).should be_true
|
58
|
+
Watercraft.instance_method(:initialize).parameters.should == [[:req, :make], [:req, :model]]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should define public class methods based on module" do
|
62
|
+
Watercraft.singleton_class.public_instance_method(:build).parameters.should == [[:rest, :args], [:block, :block]]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should define protected class methods based on module" do
|
66
|
+
Watercraft.singleton_class.protected_instance_methods.include?(:run).should be_true
|
67
|
+
Watercraft.singleton_class.instance_method(:run).parameters.should == []
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should define private class methods based on module" do
|
71
|
+
Watercraft.singleton_class.private_instance_methods.include?(:helper).should be_true
|
72
|
+
Watercraft.singleton_class.instance_method(:helper).parameters.should == [[:req, :object]]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should define all public instance methods to raise an error when called directly" do
|
76
|
+
JetSki = Class.new do
|
77
|
+
include Watercraft
|
78
|
+
|
79
|
+
def initialize(make, model)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
jet_ski = JetSki.new("Kawasaki","Ultra 300LX")
|
84
|
+
|
85
|
+
expect { jet_ski.start }.to raise_error(NotImplementedError)
|
86
|
+
expect { jet_ski.stop }.to raise_error(NotImplementedError)
|
87
|
+
expect { jet_ski.accellerate(10) }.to raise_error(NotImplementedError)
|
88
|
+
expect { jet_ski.turn(90, -5) }.to raise_error(NotImplementedError)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should define all protected instance methods to raise an error when called directly" do
|
92
|
+
OceanLiner = Class.new do
|
93
|
+
include Watercraft
|
94
|
+
|
95
|
+
def initialize(make, model)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
expect { OceanLiner.new("RMS","Titanic").send(:repair, "stern") }.to raise_error(NotImplementedError)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should define all private instance methods to raise an error when called directly" do
|
103
|
+
RowBoat = Class.new do
|
104
|
+
include Watercraft
|
105
|
+
end
|
106
|
+
|
107
|
+
expect { RowBoat.new("Freebooter","Row Boat") }.to raise_error(NotImplementedError)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should define all public class methods to raise an error when called directly" do
|
111
|
+
Automobile = Module.new do
|
112
|
+
adheres_to Vehicle::ClassMethods
|
113
|
+
end
|
114
|
+
|
115
|
+
expect { Automobile.build("Cadillac") {|c| c.year = 2012} }.to raise_error(NotImplementedError)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should define all protected class methods to raise an error when called directly" do
|
119
|
+
Locomotive = Module.new do
|
120
|
+
adheres_to Vehicle::ClassMethods
|
121
|
+
end
|
122
|
+
|
123
|
+
expect { Locomotive.send(:run) }.to raise_error(NotImplementedError)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should define all private class methods to raise an error when called directly" do
|
127
|
+
Bicycle = Module.new do
|
128
|
+
adheres_to Vehicle::ClassMethods
|
129
|
+
end
|
130
|
+
|
131
|
+
expect { Bicycle.send(:helper, "object") }.to raise_error(NotImplementedError)
|
132
|
+
end
|
133
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: adherence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mike Bradford
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.11.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.11.0
|
30
|
+
description:
|
31
|
+
email: mbradford@47primes.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- ./adherence.gemspec
|
37
|
+
- ./Gemfile
|
38
|
+
- ./Gemfile.lock
|
39
|
+
- ./lib/adherence/class.rb
|
40
|
+
- ./lib/adherence/module.rb
|
41
|
+
- ./lib/adherence.rb
|
42
|
+
- ./README.md
|
43
|
+
- ./spec/adherence_module_spec.rb
|
44
|
+
- ./spec/adherence_class_spec.rb
|
45
|
+
- spec/adherence_module_spec.rb
|
46
|
+
- spec/adherence_class_spec.rb
|
47
|
+
homepage: http://github.com/47primes/adherence
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.23
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Adds simple interface-like behavior to Ruby
|
71
|
+
test_files:
|
72
|
+
- spec/adherence_module_spec.rb
|
73
|
+
- spec/adherence_class_spec.rb
|