cenum 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE.txt +17 -0
- data/README.md +122 -0
- data/lib/cenum.rb +54 -0
- data/lib/version.rb +5 -0
- data/spec/cenum_spec.rb +71 -0
- data/spec/spec_helper.rb +4 -0
- metadata +73 -0
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
2
|
+
of this software and associated documentation files (the "Software"), to deal
|
3
|
+
in the Software without restriction, including without limitation the rights
|
4
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
5
|
+
copies of the Software, and to permit persons to whom the Software is
|
6
|
+
furnished to do so, subject to the following conditions:
|
7
|
+
|
8
|
+
The above copyright notice and this permission notice shall be included in
|
9
|
+
all copies or substantial portions of the Software.
|
10
|
+
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
12
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
14
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
15
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
16
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
17
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# C-style enums for ruby
|
2
|
+
|
3
|
+
This project is an attempt to provide c-style enums for ruby. It's obviously impossible (and not even desirable) to capture the exact syntax and semantics of c's enums in a ruby implementation, but the major capabilities and usage patterns are supported.
|
4
|
+
|
5
|
+
## But ruby has symbols, why do we need enums?
|
6
|
+
|
7
|
+
Symbols are great. You should probably keep on using symbols in most of the places that you currently do. There are, however, certain situations that enums are better suited for. For instance:
|
8
|
+
|
9
|
+
* A variable can take on a finite set of known, named, values.
|
10
|
+
> The set of values that a variable can take on define that variable's type. Rather than just scattering symbols throughout your code that modifes the variable, it is frequently helpful to encapsulate the type information in one place. An enum, being a lightweight, in-line class definition, is an ideal place to do this. Examples of this type of situation would be when you need to represent days-of-the-week or drink sizes available
|
11
|
+
DayOfWeek = enum :sun, :mon, :tues, :wed, :thurs, :fri, :sat
|
12
|
+
DrinkSize = enum :small, :medium, :large
|
13
|
+
* A dual name/value representation is needed. This is particularly common when you have a set of possible values with an inherent ordering.
|
14
|
+
> Enums have the property of defining both names and values, so you can sometimes get the best of both worlds by using them.
|
15
|
+
DrinkSize = enum :small, :medium, :large
|
16
|
+
DrinkSize::SMALL < DrinkSize::LARGE # true
|
17
|
+
|
18
|
+
## Basic Usage
|
19
|
+
|
20
|
+
require 'cenum'
|
21
|
+
|
22
|
+
class PetOwner
|
23
|
+
|
24
|
+
Animals = enum :cat, :dog, :bird
|
25
|
+
|
26
|
+
def initialize(animal)
|
27
|
+
@animal = animal || Animals::DOG
|
28
|
+
end
|
29
|
+
|
30
|
+
def pet_says
|
31
|
+
case @animal
|
32
|
+
when Animals::CAT then 'meow'
|
33
|
+
when Animals::DOG then 'woof'
|
34
|
+
when Animals::BIRD then 'tweet'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
bird_owner = PetOwner.new(PetOwner::Animals::BIRD)
|
41
|
+
|
42
|
+
bird_owner.pet_says # 'tweet'
|
43
|
+
|
44
|
+
## Features
|
45
|
+
|
46
|
+
* Enums contain a list of their values
|
47
|
+
|
48
|
+
irb> Directions = enum :up, :down, :left, :right
|
49
|
+
irb> Directions.values
|
50
|
+
[:up, :down, :left, :right]
|
51
|
+
|
52
|
+
* Enum values map to integers
|
53
|
+
|
54
|
+
irb> Directions::UP
|
55
|
+
0
|
56
|
+
irb> Directions::DOWN
|
57
|
+
1
|
58
|
+
|
59
|
+
* Enum declaration is type declaration
|
60
|
+
|
61
|
+
irb> Boolean = enum :true, :false
|
62
|
+
irb> yes = Boolean.new(:true)
|
63
|
+
irb> no = Boolean.new(:false)
|
64
|
+
irb> yes == no
|
65
|
+
false
|
66
|
+
|
67
|
+
* Value checks and mutators generated automatically
|
68
|
+
|
69
|
+
irb> Boolean = enum :true, :false
|
70
|
+
irb> yes = Boolean.new(:true)
|
71
|
+
irb> no = Boolean.new(:false)
|
72
|
+
irb> yes.true?
|
73
|
+
true
|
74
|
+
irb> no.true?
|
75
|
+
false
|
76
|
+
irb> maybe = Boolean.new(:true)
|
77
|
+
irb> maybe == yes
|
78
|
+
true
|
79
|
+
irb> maybe.false!
|
80
|
+
irb> maybe == yes
|
81
|
+
false
|
82
|
+
irb> maybe == no
|
83
|
+
true
|
84
|
+
|
85
|
+
* Direct comparison of type instances with value names
|
86
|
+
|
87
|
+
irb> Boolean = enum :true, :false
|
88
|
+
irb> yes = Boolean.new(:true)
|
89
|
+
irb> yes == Boolean::TRUE
|
90
|
+
true
|
91
|
+
irb> yes != Boolean::FALSE
|
92
|
+
true
|
93
|
+
|
94
|
+
* Values can be compared
|
95
|
+
|
96
|
+
irb> up = Directions.new(:up)
|
97
|
+
irb> down = Directions.new(:down)
|
98
|
+
irb> up < down
|
99
|
+
true
|
100
|
+
|
101
|
+
* Values can be compared to their names
|
102
|
+
|
103
|
+
irb> up == :up
|
104
|
+
true
|
105
|
+
|
106
|
+
* Custom value mappings
|
107
|
+
|
108
|
+
irb> Drinks = enum :small, :medium, :large, :infinite => -1
|
109
|
+
irb> Drinks::SMALL
|
110
|
+
0
|
111
|
+
irb> Drinks::MEDIUM
|
112
|
+
1
|
113
|
+
irb> Drinks::INFINITE
|
114
|
+
-1
|
115
|
+
|
116
|
+
## Roadmap
|
117
|
+
|
118
|
+
* Improve custom value mappings
|
119
|
+
* Spec
|
120
|
+
* Prevent collisions
|
121
|
+
* Allow non-integer value mappings
|
122
|
+
* Consider using a DSL to improve syntax (gets messy in some cases currently)
|
data/lib/cenum.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
class Enum
|
4
|
+
|
5
|
+
def self.constant_name(name)
|
6
|
+
name.to_s.upcase
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.[](name)
|
10
|
+
const_get(constant_name(name))
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@value = self.class[name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def <=>(other)
|
18
|
+
case other
|
19
|
+
when Enum
|
20
|
+
@value <=> other.__value__
|
21
|
+
when String, Symbol
|
22
|
+
@value <=> self.class[other]
|
23
|
+
else
|
24
|
+
@value <=> other
|
25
|
+
end
|
26
|
+
end
|
27
|
+
include Comparable
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def __value__
|
32
|
+
@value
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def enum(*names)
|
38
|
+
klass = Class.new(Enum)
|
39
|
+
counter = 0
|
40
|
+
names.each do |name|
|
41
|
+
if name.is_a? Hash
|
42
|
+
counter = name.values.first
|
43
|
+
name = name.keys.first
|
44
|
+
end
|
45
|
+
klass.const_set(klass.constant_name(name), counter)
|
46
|
+
klass.send(:define_method, "#{name}?", lambda { @value == klass[name] })
|
47
|
+
klass.send(:define_method, "#{name}!", lambda { @value = klass[name] })
|
48
|
+
counter += 1
|
49
|
+
end
|
50
|
+
(class << klass ; self ; end).send(:define_method, :values){ names }
|
51
|
+
klass
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/version.rb
ADDED
data/spec/cenum_spec.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'enum' do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@enum = enum :val1, :val2
|
7
|
+
end
|
8
|
+
|
9
|
+
it "is a class" do
|
10
|
+
@enum.should be_a(Class)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "includes its values as constants" do
|
14
|
+
@enum.constants.should include(:VAL1)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "are its values accessible using #values" do
|
18
|
+
@enum.values.should == [:val1, :val2]
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'value' do
|
22
|
+
|
23
|
+
it "are Fixnum" do
|
24
|
+
@enum::VAL1.should == 0
|
25
|
+
@enum::VAL2.should == 1
|
26
|
+
end
|
27
|
+
|
28
|
+
it "can be instantiated" do
|
29
|
+
val1 = @enum.new(:val1)
|
30
|
+
val1.should be_a(@enum)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "instantiated" do
|
34
|
+
|
35
|
+
before :each do
|
36
|
+
@val1 = @enum.new(:val1)
|
37
|
+
@val2 = @enum.new(:val2)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can be compared" do
|
41
|
+
@val1.should == @val1
|
42
|
+
@val1.should_not == @val2
|
43
|
+
@val1.should < @val2
|
44
|
+
end
|
45
|
+
|
46
|
+
it "has value? getter" do
|
47
|
+
@val1.should respond_to(:val1?)
|
48
|
+
@val1.val1?.should be_true
|
49
|
+
@val1.val2?.should be_false
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can change its value" do
|
53
|
+
@val1.should respond_to(:val2!)
|
54
|
+
@val1.val2!
|
55
|
+
@val1.should == @val2
|
56
|
+
end
|
57
|
+
|
58
|
+
it "can be compared to values" do
|
59
|
+
@val1.should == @enum::VAL1
|
60
|
+
@val1.should_not == @enum::VAL2
|
61
|
+
end
|
62
|
+
|
63
|
+
it "can be compared to values name" do
|
64
|
+
@val1.should == :val1
|
65
|
+
end
|
66
|
+
|
67
|
+
end # instantiated
|
68
|
+
|
69
|
+
end # value
|
70
|
+
|
71
|
+
end # enum
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cenum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Shane Gibbons
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-06-12 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email:
|
23
|
+
- shane.r.gibbons@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- README.md
|
32
|
+
- MIT-LICENSE.txt
|
33
|
+
- lib/version.rb
|
34
|
+
- lib/cenum.rb
|
35
|
+
- spec/spec_helper.rb
|
36
|
+
- spec/cenum_spec.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: https://github.com/microsage/cenum
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 3
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.5.2
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: This project is an attempt to provide c-style enums for ruby. It's obviously impossible (and not even desirable) to capture the exact syntax and semantics of c's enums in a ruby implementation, but the major capabilities and usage patterns are supported.
|
71
|
+
test_files:
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
- spec/cenum_spec.rb
|