enumerated_type 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MGRiNTE1NTQ1ZjI5N2IwMGM4ZmVlNjEzYjFhYjNjMGFkNDY1MjdiYQ==
5
+ data.tar.gz: !binary |-
6
+ NDM3MDI1NjczOTVmY2E2ZmQwOTQyZWYxMzk5NWFkNTZmNjFlNTdhZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGU1MjA4OGRkYTU4MDU2MjdlMmI0MjM1NzYwMWRiYTk5Mzg4ZjNiYjgxZjll
10
+ NDQxNWM1NTA2MjZmYTU4ZmQ5NTJiZjA3Mjk2ZGNlMmUyNGRlYTFhNWU2Njk5
11
+ MWM1MjM2MDBmNTE0MzQ2YmI5OGYyNmVmNGUyNjQzZWM1ZWQ3N2M=
12
+ data.tar.gz: !binary |-
13
+ NDA5MzBmYmNjN2UyMGFlZjA2YTIwYmIzYjVlNjRjMGM2N2YwYjA3ZWFlNDAw
14
+ ZDk0OTNlYjk3YTRkNDY4NmUwODg0NjIwMDdiODU4YmZiMDFhZjJkZmMwZmE1
15
+ MjFkYmFjYzg3MDA1MmZlYjhkY2JmYzExM2JhMmYyYTNlNGUzNzI=
data/README.md CHANGED
@@ -36,7 +36,7 @@ if job.status == :failure or job.status == :success
36
36
  end
37
37
  ```
38
38
 
39
- At this point, it's starting to feel like a little bit too much knowledge about the `Job` has slipped into other classes; any changes to the in the way status is handled in `Job` will require change in other classes because they've been exposed to the details of it's implementation. What, for example, if we want to add another "finished" state that a user should be notified of (say, `:partial_success`)? To deal with this we might create a predicate method that lets you interrogate a `Job` more abstractly about it's status:
39
+ At this point, its starting to feel like a little bit too much knowledge about the `Job` has slipped into other classes; any changes to the in the way status is handled in `Job` will require change in other classes because they've been exposed to the details of its implementation. What, for example, if we want to add another "finished" state that a user should be notified of (say, `:partial_success`)? To deal with this we might create a predicate method that lets you interrogate a `Job` more abstractly about it's status:
40
40
 
41
41
  ```ruby
42
42
  class Job
@@ -47,7 +47,7 @@ class Job
47
47
  end
48
48
  ```
49
49
 
50
- Now, say we need another kind of job: the `AdminJob`. It needs to have the same set of statuses (with the same behavior as `Job`'s status). We could certainly move the status related code into a `StatusHaving` module and mix it in to both `Job` and `AdminJob`, but there are some drawbacks here, chief among them that we'd have to add a good bit of coupling between the `Job`, `AdminJob` and the `StatusHaving` mix-in module. For example both classes and the mix-in would need to agree on the `@status` instance variable. I would argue at this point the idea of a `JobStatus` should be promoted to it's own class, maybe with a little bit of error checking:
50
+ Now, say we need another kind of job: the `AdminJob`. It needs to have the same set of statuses (with the same behavior as `Job`'s status). We could certainly move the status related code into a `StatusHaving` module and mix it in to both `Job` and `AdminJob`, but there are some drawbacks here, chief among them that we'd have to add a good bit of coupling between the `Job`, `AdminJob` and the `StatusHaving` mix-in module. For example both classes and the mix-in would need to agree on the `@status` instance variable. I would argue at this point the idea of a `JobStatus` should be promoted to its own class, maybe with a little bit of error checking:
51
51
 
52
52
  ```ruby
53
53
  class JobStatus
@@ -182,7 +182,7 @@ JobStatus.by(:code, 2) # => #<JobStatus:success>
182
182
  JobStatus.by(:code, 4) # => raises a TypeError
183
183
  ```
184
184
 
185
- The first parameter specifies the method that will be called on instances of your `EnumeratedType` during lookup. This works for attributes specified with `declare` (such as `:code` above) but also for .
185
+ The first parameter specifies the method that will be called on instances of your `EnumeratedType` during lookup. This works for attributes specified with `declare` (such as `:code` above) but also for any instance method on your `EnumeratedType`.
186
186
 
187
187
  ```ruby
188
188
  class JobStatus
@@ -193,7 +193,7 @@ end
193
193
 
194
194
  JobStatus.by(:display, "pending-1") # => #<JobStatus:pending>
195
195
  ```
196
- If more than one instance of your `EnumeratedType` matches, the first match will be returned in the order the types were `declared`.
196
+ If more than one instance of your `EnumeratedType` matches, the first match will be returned, in the order the types were `declared`.
197
197
 
198
198
  ## Development
199
199
 
@@ -1,9 +1,33 @@
1
1
  require "enumerated_type/version"
2
2
 
3
3
  module EnumeratedType
4
+ class ByCache
5
+ def initialize
6
+ self.by_property = { }
7
+ end
8
+
9
+ def set(property, value, enumerated)
10
+ by_value = (by_property[property.to_sym] ||= { })
11
+ by_value[value] ||= enumerated
12
+ end
13
+
14
+ def get(property, value, miss)
15
+ by_property.fetch(property.to_sym).fetch(value, &miss)
16
+ end
17
+
18
+ def has_property?(property)
19
+ by_property.has_key?(property.to_sym)
20
+ end
21
+
22
+ private
23
+
24
+ attr_accessor :by_property
25
+ end
26
+
4
27
  def self.included(base)
5
28
  base.instance_eval do
6
29
  @all = []
30
+ @by_cache = ByCache.new
7
31
 
8
32
  attr_reader :name, :value
9
33
 
@@ -52,9 +76,14 @@ module EnumeratedType
52
76
  @all.each(&block)
53
77
  end
54
78
 
55
- def by(name, value)
56
- found = find { |e| e.send(name) == value }
57
- found || raise(ArgumentError, "Could not find #{self.name} with ##{name} == #{value.inspect}'")
79
+ def by(property, value, &miss)
80
+ miss ||= Proc.new { raise(ArgumentError, "Could not find #{self.name} with ##{property} == #{value.inspect}'") }
81
+
82
+ if @by_cache.has_property?(property)
83
+ @by_cache.get(property, value, miss)
84
+ else
85
+ find { |e| e.send(property) == value } || miss.call
86
+ end
58
87
  end
59
88
 
60
89
  def [](name)
@@ -78,7 +107,7 @@ module EnumeratedType
78
107
  private
79
108
 
80
109
  def declare(name, options = {})
81
- if map(&:name).include?(name)
110
+ unless by(:name, name) { :not_found } == :not_found
82
111
  raise(ArgumentError, "duplicate name #{name.inspect}")
83
112
  end
84
113
 
@@ -91,18 +120,16 @@ module EnumeratedType
91
120
  raise ArgumentError, "Property name 'name' is not allowed (conflicts with default EnumeratedType#name)"
92
121
  end
93
122
 
94
- unless instance_methods.include?(:"#{property}")
95
- attr_reader(:"#{property}")
96
- end
97
-
98
- unless instance_methods.include?(:"#{property}=")
99
- attr_writer(:"#{property}")
100
- private(:"#{property}=")
101
- end
123
+ attr_accessor(:"#{property}")
124
+ private(:"#{property}=")
102
125
  end
103
126
 
104
127
  enumerated = new(name, options).freeze
105
128
 
129
+ (options.keys + [:name]).each do |property|
130
+ @by_cache.set(property, enumerated.send(property), enumerated)
131
+ end
132
+
106
133
  @all << enumerated
107
134
  const_set(name.to_s.upcase, enumerated)
108
135
  end
@@ -1,3 +1,3 @@
1
1
  module EnumeratedType
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -190,10 +190,14 @@ describe EnumeratedType do
190
190
  Shapes.by(:sides, 4).must_equal(Shapes::RECTANGLE)
191
191
  end
192
192
 
193
- it "raises an argumetn if there is no match" do
193
+ it "raises an argument if there is no match" do
194
194
  lambda { Shapes.by(:sides, 6) }.must_raise(ArgumentError)
195
195
  end
196
196
 
197
+ it "executes (and returns) the block if there is no match" do
198
+ (Shapes.by(:sides, 6) { "UnknownShape"}).must_equal("UnknownShape")
199
+ end
200
+
197
201
  it "returns the first declared value if there is more than one match" do
198
202
  Shapes.by(:pretty_hip, "YEAH").must_equal(Shapes::TRIANGLE)
199
203
  end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerated_type
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Rafer Hazen
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-03-28 00:00:00.000000000 Z
11
+ date: 2014-09-11 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: minitest
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rake
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
@@ -78,33 +71,26 @@ files:
78
71
  homepage: https://github.com/rafer/enumerated_type
79
72
  licenses:
80
73
  - MIT
74
+ metadata: {}
81
75
  post_install_message:
82
76
  rdoc_options: []
83
77
  require_paths:
84
78
  - lib
85
79
  required_ruby_version: !ruby/object:Gem::Requirement
86
- none: false
87
80
  requirements:
88
81
  - - ! '>='
89
82
  - !ruby/object:Gem::Version
90
83
  version: '0'
91
- segments:
92
- - 0
93
- hash: 2282385263752842432
94
84
  required_rubygems_version: !ruby/object:Gem::Requirement
95
- none: false
96
85
  requirements:
97
86
  - - ! '>='
98
87
  - !ruby/object:Gem::Version
99
88
  version: '0'
100
- segments:
101
- - 0
102
- hash: 2282385263752842432
103
89
  requirements: []
104
90
  rubyforge_project:
105
- rubygems_version: 1.8.23
91
+ rubygems_version: 2.3.0
106
92
  signing_key:
107
- specification_version: 3
93
+ specification_version: 4
108
94
  summary: Simple enumerated types
109
95
  test_files:
110
96
  - test/enumerated_type_spec.rb