abstraction 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/README.markdown +5 -1
- data/Rakefile +13 -0
- data/VERSION.yml +1 -1
- data/examples/cars.rb +32 -0
- data/lib/abstraction.rb +2 -2
- data/spec/abstraction_spec.rb +21 -2
- data/spec/spec.opts +0 -1
- metadata +11 -8
data/History.txt
ADDED
data/README.markdown
CHANGED
@@ -25,6 +25,10 @@ How would you write `Car#doors`? You wouldn't, because unlike moving forward, t
|
|
25
25
|
|
26
26
|
But what's stopping us? Nothing. And that's a problem. So let's fix it:
|
27
27
|
|
28
|
+
$ sudo gem install abstraction
|
29
|
+
|
30
|
+
Then:
|
31
|
+
|
28
32
|
require 'abstraction'
|
29
33
|
|
30
34
|
class Car
|
@@ -117,7 +121,7 @@ But as we've seen, Abstraction clears that all up. Just make the class abstract
|
|
117
121
|
Abstract Methods
|
118
122
|
================
|
119
123
|
|
120
|
-
(Warning: this section is a bit of a tease.)
|
124
|
+
*(Warning: this section is a bit of a tease.)*
|
121
125
|
|
122
126
|
Traditionally, abstract classes are found in strongly typed languages, where the compiler makes sure they're never created by type checking. In the Ruby world, the test suite is essentially our type checker. No complier can statically prove that an abstract Ruby class will never be instantiated, but we can exercise the test suite and see if it ever happens.
|
123
127
|
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |s|
|
4
|
+
s.name = "abstraction"
|
5
|
+
s.description = s.summary = "Abstract classes for Ruby"
|
6
|
+
s.authors = ["Peter Jaros"]
|
7
|
+
s.email = "peter.a.jaros@gmail.com"
|
8
|
+
s.homepage = "http://github.com/Peeja/abstraction"
|
9
|
+
s.rubyforge_project = "abstraction"
|
10
|
+
end
|
11
|
+
rescue LoadError
|
12
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
13
|
+
end
|
data/VERSION.yml
CHANGED
data/examples/cars.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'abstraction'
|
3
|
+
|
4
|
+
class Car
|
5
|
+
abstract
|
6
|
+
end
|
7
|
+
|
8
|
+
class Convertible < Car
|
9
|
+
def door_count
|
10
|
+
2
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Sedan < Car
|
15
|
+
def door_count
|
16
|
+
4
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Either of these will raise an error, because Car is abstract.
|
21
|
+
|
22
|
+
# Car.new
|
23
|
+
# Car.allocate
|
24
|
+
|
25
|
+
|
26
|
+
# These cause no problems.
|
27
|
+
|
28
|
+
Convertible.new
|
29
|
+
Convertible.allocate
|
30
|
+
|
31
|
+
Sedan.new
|
32
|
+
Sedan.allocate
|
data/lib/abstraction.rb
CHANGED
@@ -21,11 +21,11 @@ class Class
|
|
21
21
|
def abstract
|
22
22
|
abstract_class = self
|
23
23
|
|
24
|
-
raise_if_abstract = lambda do
|
24
|
+
raise_if_abstract = lambda do |*args, &block|
|
25
25
|
if self == abstract_class
|
26
26
|
raise AbstractClassError, "#{self} is an abstract class and cannot be instantiated"
|
27
27
|
else
|
28
|
-
super
|
28
|
+
super *args, &block
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
data/spec/abstraction_spec.rb
CHANGED
@@ -5,11 +5,22 @@ $: << File.join(File.dirname(__FILE__), '..', 'lib')
|
|
5
5
|
require 'abstraction'
|
6
6
|
|
7
7
|
describe "#abstract" do
|
8
|
-
|
8
|
+
# Similar to ActiveRecord::Base.new
|
9
|
+
class Organism
|
10
|
+
def self.new(&b)
|
11
|
+
o = super
|
12
|
+
yield o if block_given?
|
13
|
+
o
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Animal < Organism
|
9
18
|
abstract
|
10
19
|
end
|
11
20
|
|
12
|
-
class Cat < Animal
|
21
|
+
class Cat < Animal
|
22
|
+
attr_accessor :fur
|
23
|
+
end
|
13
24
|
|
14
25
|
it "makes a class non-instantiable via new" do
|
15
26
|
lambda {
|
@@ -29,6 +40,14 @@ describe "#abstract" do
|
|
29
40
|
}.should_not raise_error(AbstractClassError)
|
30
41
|
end
|
31
42
|
|
43
|
+
it "lets subclasses be instantiated via new with a block" do
|
44
|
+
cat = nil
|
45
|
+
lambda {
|
46
|
+
cat = Cat.new { |c| c.fur = :tabby }
|
47
|
+
}.should_not raise_error(AbstractClassError)
|
48
|
+
cat.fur.should == :tabby
|
49
|
+
end
|
50
|
+
|
32
51
|
it "lets subclasses be instantiated via allocate" do
|
33
52
|
lambda {
|
34
53
|
Cat.new
|
data/spec/spec.opts
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
--color
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abstraction
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Jaros
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-12 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -19,11 +19,14 @@ executables: []
|
|
19
19
|
|
20
20
|
extensions: []
|
21
21
|
|
22
|
-
extra_rdoc_files:
|
23
|
-
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.markdown
|
24
24
|
files:
|
25
|
+
- History.txt
|
25
26
|
- README.markdown
|
27
|
+
- Rakefile
|
26
28
|
- VERSION.yml
|
29
|
+
- examples/cars.rb
|
27
30
|
- lib/abstraction.rb
|
28
31
|
- spec/abstraction_spec.rb
|
29
32
|
- spec/spec.opts
|
@@ -31,7 +34,6 @@ has_rdoc: true
|
|
31
34
|
homepage: http://github.com/Peeja/abstraction
|
32
35
|
post_install_message:
|
33
36
|
rdoc_options:
|
34
|
-
- --inline-source
|
35
37
|
- --charset=UTF-8
|
36
38
|
require_paths:
|
37
39
|
- lib
|
@@ -49,10 +51,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
51
|
version:
|
50
52
|
requirements: []
|
51
53
|
|
52
|
-
rubyforge_project:
|
54
|
+
rubyforge_project: abstraction
|
53
55
|
rubygems_version: 1.3.1
|
54
56
|
signing_key:
|
55
57
|
specification_version: 2
|
56
58
|
summary: Abstract classes for Ruby
|
57
|
-
test_files:
|
58
|
-
|
59
|
+
test_files:
|
60
|
+
- spec/abstraction_spec.rb
|
61
|
+
- examples/cars.rb
|