cenum 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -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)
@@ -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
@@ -0,0 +1,5 @@
1
+ module Kernel
2
+ class Enum
3
+ VERSION = "0.1"
4
+ end
5
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ require File.join(File.dirname(__FILE__), '../lib', 'cenum')
2
+
3
+ require 'rspec'
4
+
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