enumerated_type 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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