characterizable 0.0.17 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.17
1
+ 0.1.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{characterizable}
8
- s.version = "0.0.17"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andy Rossmeissl", "Seamus Abshere"]
12
- s.date = %q{2010-09-30}
12
+ s.date = %q{2010-11-03}
13
13
  s.description = %q{Characterize the relationship between "attributes" (getters/setters) of instances of a class}
14
14
  s.email = %q{seamus@abshere.net}
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,11 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "characterizable.gemspec",
27
27
  "lib/characterizable.rb",
28
+ "lib/characterizable/base.rb",
29
+ "lib/characterizable/better_hash.rb",
30
+ "lib/characterizable/characteristic.rb",
31
+ "lib/characterizable/snapshot.rb",
32
+ "test/characterizable/test_characteristic.rb",
28
33
  "test/helper.rb",
29
34
  "test/test_characterizable.rb"
30
35
  ]
@@ -34,7 +39,8 @@ Gem::Specification.new do |s|
34
39
  s.rubygems_version = %q{1.3.7}
35
40
  s.summary = %q{Characterize instances of a class}
36
41
  s.test_files = [
37
- "test/helper.rb",
42
+ "test/characterizable/test_characteristic.rb",
43
+ "test/helper.rb",
38
44
  "test/test_characterizable.rb"
39
45
  ]
40
46
 
@@ -12,6 +12,12 @@ require 'active_support/version'
12
12
  require active_support_3_requirement
13
13
  end if ActiveSupport::VERSION::MAJOR == 3
14
14
 
15
+ $:.unshift File.dirname(__FILE__)
16
+ require 'characterizable/base'
17
+ require 'characterizable/better_hash'
18
+ require 'characterizable/characteristic'
19
+ require 'characterizable/snapshot'
20
+
15
21
  module Characterizable
16
22
  def self.included(klass)
17
23
  klass.cattr_accessor :characterizable_base
@@ -25,93 +31,10 @@ module Characterizable
25
31
  def expire_snapshot!
26
32
  @_characteristics = nil
27
33
  end
28
-
29
- class BetterHash < ::Hash
30
- # In Ruby 1.9, running select/reject/etc. gives you back a hash
31
- # if RUBY_VERSION < '1.9'
32
- def to_hash
33
- Hash.new.replace self
34
- end
35
- def as_json(*)
36
- to_hash
37
- end
38
- def reject(&block)
39
- inject(Characterizable::BetterHash.new) do |memo, ary|
40
- unless block.call(*ary)
41
- memo[ary[0]] = ary[1]
42
- end
43
- memo
44
- end
45
- end
46
- def select(&block)
47
- inject(Characterizable::BetterHash.new) do |memo, ary|
48
- if block.call(*ary)
49
- memo[ary[0]] = ary[1]
50
- end
51
- memo
52
- end
53
- end
54
- # I need this because otherwise it will try to do self.class.new on subclasses
55
- # which would get "0 for 1" arguments error with Snapshot, among other things
56
- def slice(*keep)
57
- inject(Characterizable::BetterHash.new) do |memo, ary|
58
- if keep.include?(ary[0])
59
- memo[ary[0]] = ary[1]
60
- end
61
- memo
62
- end
63
- end
64
- # end
65
- end
66
-
67
- class Snapshot < BetterHash
68
- attr_reader :universe
69
- def initialize(universe)
70
- @universe = universe
71
- _take_snapshot
72
- end
73
- def _take_snapshot
74
- universe.characterizable_base.characteristics.each do |_, c|
75
- if c.known?(universe)
76
- if c.effective?(universe)
77
- self[c.name] = c.value(universe)
78
- elsif c.trumped?(universe)
79
- trumped_keys.push c.name
80
- elsif !c.revealed?(universe)
81
- wasted_keys.push c.name
82
- lacking_keys.push c.prerequisite
83
- end
84
- end
85
- end
86
- end
87
- def []=(key, value)
88
- universe.expire_snapshot!
89
- super
90
- end
91
- def wasted_keys
92
- @wasted_keys ||= Array.new
93
- end
94
- def trumped_keys
95
- @trumped_keys ||= Array.new
96
- end
97
- def lacking_keys
98
- @lacking_keys ||= Array.new
99
- end
100
- def effective
101
- universe.characterizable_base.characteristics.select { |_, c| c.effective?(self) }
102
- end
103
- def potential
104
- universe.characterizable_base.characteristics.select { |_, c| c.potential?(self) }
105
- end
106
- def wasted
107
- universe.characterizable_base.characteristics.slice(*wasted_keys)
108
- end
109
- def lacking
110
- universe.characterizable_base.characteristics.slice(*(lacking_keys - wasted_keys))
111
- end
112
- def trumped
113
- universe.characterizable_base.characteristics.slice(*trumped_keys)
114
- end
34
+
35
+ def display_characteristic(name)
36
+ characteristic = self.class.characteristics[name]
37
+ characteristic.display(characteristics) if characteristic
115
38
  end
116
39
 
117
40
  module ClassMethods
@@ -124,99 +47,5 @@ module Characterizable
124
47
  end
125
48
  end
126
49
 
127
- class CharacteristicAlreadyDefined < ArgumentError
128
- end
129
-
130
- class Base
131
- attr_reader :klass
132
- def initialize(klass)
133
- @klass = klass
134
- end
135
- def characteristics
136
- @_characteristics ||= BetterHash.new
137
- end
138
- include Blockenspiel::DSL
139
- def has(name, options = {}, &block)
140
- raise CharacteristicAlreadyDefined, "The characteristic #{name} has already been defined on #{klass}!" if characteristics.has_key?(name)
141
- characteristics[name] = Characteristic.new(self, name, options, &block)
142
- begin
143
- # quacks like an activemodel
144
- klass.define_attribute_methods unless klass.respond_to?(:attribute_methods_generated?) and klass.attribute_methods_generated?
145
- rescue
146
- # for example, if a table doesn't exist... just ignore it
147
- end
148
- begin
149
- klass.module_eval(%{
150
- def #{name}_with_expire_snapshot=(new_#{name})
151
- expire_snapshot!
152
- self.#{name}_without_expire_snapshot = new_#{name}
153
- end
154
- alias_method_chain :#{name}=, :expire_snapshot
155
- }, __FILE__, __LINE__) #if klass.instance_methods.include?("#{name}=")
156
- rescue
157
- end
158
- end
159
- end
160
- class Characteristic
161
- attr_reader :base
162
- attr_reader :name
163
- attr_reader :trumps
164
- attr_reader :prerequisite
165
- attr_reader :options
166
- def initialize(base, name, options = {}, &block)
167
- @base = base
168
- @name = name
169
- @trumps = Array.wrap options.delete(:trumps)
170
- @prerequisite = options.delete(:prerequisite)
171
- @options = options
172
- Blockenspiel.invoke block, self if block_given?
173
- end
174
- def as_json(*)
175
- { :name => name, :trumps => trumps, :prerequisite => prerequisite, :options => options }
176
- end
177
- def inspect
178
- "<Characterizable::Characteristic name=#{name.inspect} trumps=#{trumps.inspect} prerequisite=#{prerequisite.inspect} options=#{options.inspect}>"
179
- end
180
- def characteristics
181
- base.characteristics
182
- end
183
- def value(universe)
184
- case universe
185
- when Hash
186
- universe[name]
187
- else
188
- universe.send name if universe.respond_to?(name)
189
- end
190
- end
191
- def known?(universe)
192
- not value(universe).nil?
193
- end
194
- def potential?(universe)
195
- not known?(universe) and revealed? universe and not trumped? universe
196
- end
197
- def effective?(universe, ignoring = nil)
198
- known?(universe) and revealed? universe and not trumped? universe, ignoring
199
- end
200
- def trumped?(universe, ignoring = nil)
201
- characteristics.each do |_, other|
202
- if other.trumps.include? name and not ignoring == other.name
203
- if trumps.include? other.name
204
- # special case: mutual trumping. current characteristic is trumped if its friend is otherwise effective and it is not otherwise effective
205
- return true if other.effective? universe, name and not effective? universe, other.name
206
- else
207
- return true if other.effective? universe
208
- end
209
- end
210
- end
211
- false
212
- end
213
- def revealed?(universe)
214
- return true if prerequisite.nil?
215
- characteristics[prerequisite].effective? universe
216
- end
217
- include Blockenspiel::DSL
218
- def reveals(other_name, other_options = {}, &block)
219
- base.has other_name, other_options.merge(:prerequisite => name), &block
220
- end
221
- end
50
+ class CharacteristicAlreadyDefined < ArgumentError; end
222
51
  end
@@ -0,0 +1,32 @@
1
+ module Characterizable
2
+ class Base
3
+ attr_reader :klass
4
+ def initialize(klass)
5
+ @klass = klass
6
+ end
7
+ def characteristics
8
+ @_characteristics ||= BetterHash.new
9
+ end
10
+ include Blockenspiel::DSL
11
+ def has(name, options = {}, &block)
12
+ raise CharacteristicAlreadyDefined, "The characteristic #{name} has already been defined on #{klass}!" if characteristics.has_key?(name)
13
+ characteristics[name] = Characteristic.new(self, name, options, &block)
14
+ begin
15
+ # quacks like an activemodel
16
+ klass.define_attribute_methods unless klass.respond_to?(:attribute_methods_generated?) and klass.attribute_methods_generated?
17
+ rescue
18
+ # for example, if a table doesn't exist... just ignore it
19
+ end
20
+ begin
21
+ klass.module_eval(%{
22
+ def #{name}_with_expire_snapshot=(new_#{name})
23
+ expire_snapshot!
24
+ self.#{name}_without_expire_snapshot = new_#{name}
25
+ end
26
+ alias_method_chain :#{name}=, :expire_snapshot
27
+ }, __FILE__, __LINE__) #if klass.instance_methods.include?("#{name}=")
28
+ rescue
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ module Characterizable
2
+ class BetterHash < ::Hash
3
+ # In Ruby 1.9, running select/reject/etc. gives you back a hash
4
+ # if RUBY_VERSION < '1.9'
5
+ def to_hash
6
+ Hash.new.replace self
7
+ end
8
+ def as_json(*)
9
+ to_hash
10
+ end
11
+ def reject(&block)
12
+ inject(Characterizable::BetterHash.new) do |memo, ary|
13
+ unless block.call(*ary)
14
+ memo[ary[0]] = ary[1]
15
+ end
16
+ memo
17
+ end
18
+ end
19
+ def select(&block)
20
+ inject(Characterizable::BetterHash.new) do |memo, ary|
21
+ if block.call(*ary)
22
+ memo[ary[0]] = ary[1]
23
+ end
24
+ memo
25
+ end
26
+ end
27
+ # I need this because otherwise it will try to do self.class.new on subclasses
28
+ # which would get "0 for 1" arguments error with Snapshot, among other things
29
+ def slice(*keep)
30
+ inject(Characterizable::BetterHash.new) do |memo, ary|
31
+ if keep.include?(ary[0])
32
+ memo[ary[0]] = ary[1]
33
+ end
34
+ memo
35
+ end
36
+ end
37
+ # end
38
+ end
39
+ end
@@ -0,0 +1,80 @@
1
+ module Characterizable
2
+ class Characteristic
3
+ attr_reader :base, :name, :trumps, :prerequisite, :display, :options
4
+
5
+ def initialize(base, name, options = {}, &block)
6
+ @base = base
7
+ @name = name
8
+ @trumps = Array.wrap options.delete(:trumps)
9
+ @prerequisite = options.delete(:prerequisite)
10
+ @display = options.delete(:display)
11
+ @options = options
12
+ Blockenspiel.invoke block, self if block_given?
13
+ end
14
+
15
+ def as_json(*)
16
+ { :name => name, :trumps => trumps, :prerequisite => prerequisite, :options => options }
17
+ end
18
+
19
+ def inspect
20
+ "<Characterizable::Characteristic name=#{name.inspect} trumps=#{trumps.inspect} prerequisite=#{prerequisite.inspect} options=#{options.inspect}>"
21
+ end
22
+
23
+ def characteristics
24
+ base.characteristics
25
+ end
26
+
27
+ def value(universe)
28
+ case universe
29
+ when Hash
30
+ universe[name]
31
+ else
32
+ universe.send name if universe.respond_to?(name)
33
+ end
34
+ end
35
+
36
+ def display(universe)
37
+ @display.call(value(universe)) if @display
38
+ end
39
+
40
+ def known?(universe)
41
+ not value(universe).nil?
42
+ end
43
+
44
+ def potential?(universe)
45
+ not known?(universe) and revealed? universe and not trumped? universe
46
+ end
47
+
48
+ def effective?(universe, ignoring = nil)
49
+ known?(universe) and revealed? universe and not trumped? universe, ignoring
50
+ end
51
+
52
+ def trumped?(universe, ignoring = nil)
53
+ characteristics.each do |_, other|
54
+ if other.trumps.include? name and not ignoring == other.name
55
+ if trumps.include? other.name
56
+ # special case: mutual trumping. current characteristic is trumped if its friend is otherwise effective and it is not otherwise effective
57
+ return true if other.effective? universe, name and not effective? universe, other.name
58
+ else
59
+ return true if other.effective? universe
60
+ end
61
+ end
62
+ end
63
+ false
64
+ end
65
+
66
+ def revealed?(universe)
67
+ return true if prerequisite.nil?
68
+ characteristics[prerequisite].effective? universe
69
+ end
70
+
71
+ include Blockenspiel::DSL
72
+ def reveals(other_name, other_options = {}, &block)
73
+ base.has other_name, other_options.merge(:prerequisite => name), &block
74
+ end
75
+
76
+ def displays(&block)
77
+ @display = block
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,51 @@
1
+ module Characterizable
2
+ class Snapshot < BetterHash
3
+ attr_reader :universe
4
+ def initialize(universe)
5
+ @universe = universe
6
+ _take_snapshot
7
+ end
8
+ def _take_snapshot
9
+ universe.characterizable_base.characteristics.each do |_, c|
10
+ if c.known?(universe)
11
+ if c.effective?(universe)
12
+ self[c.name] = c.value(universe)
13
+ elsif c.trumped?(universe)
14
+ trumped_keys.push c.name
15
+ elsif !c.revealed?(universe)
16
+ wasted_keys.push c.name
17
+ lacking_keys.push c.prerequisite
18
+ end
19
+ end
20
+ end
21
+ end
22
+ def []=(key, value)
23
+ universe.expire_snapshot!
24
+ super
25
+ end
26
+ def wasted_keys
27
+ @wasted_keys ||= Array.new
28
+ end
29
+ def trumped_keys
30
+ @trumped_keys ||= Array.new
31
+ end
32
+ def lacking_keys
33
+ @lacking_keys ||= Array.new
34
+ end
35
+ def effective
36
+ universe.characterizable_base.characteristics.select { |_, c| c.effective?(self) }
37
+ end
38
+ def potential
39
+ universe.characterizable_base.characteristics.select { |_, c| c.potential?(self) }
40
+ end
41
+ def wasted
42
+ universe.characterizable_base.characteristics.slice(*wasted_keys)
43
+ end
44
+ def lacking
45
+ universe.characterizable_base.characteristics.slice(*(lacking_keys - wasted_keys))
46
+ end
47
+ def trumped
48
+ universe.characterizable_base.characteristics.slice(*trumped_keys)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ require 'helper'
2
+
3
+ class Character
4
+ include Characterizable
5
+ end
6
+
7
+ class Characterizable::CharacteristicTest < Test::Unit::TestCase
8
+ context 'display' do
9
+ setup do
10
+ @universe = { :charisma => 'hearty' }
11
+ end
12
+
13
+ should 'not display a custom format if display option not given' do
14
+ char = Characterizable::Characteristic.new(Character, :charisma, {})
15
+ assert_nil char.display(@universe)
16
+ end
17
+ should 'display a custom format if display option is given' do
18
+ char = Characterizable::Characteristic.new(Character, :charisma,
19
+ { :display => lambda { |c| "Level: #{c}" } }) {}
20
+ assert_equal 'Level: hearty', char.display(@universe)
21
+ end
22
+ end
23
+ end
@@ -39,13 +39,14 @@ end
39
39
 
40
40
  class SimpleAutomobile
41
41
  include Characterizable
42
- attr_accessor :make
43
- attr_accessor :model
44
- attr_accessor :variant
42
+ attr_accessor :make, :model, :variant
43
+
45
44
  characterize do
46
45
  has :make
47
- has :model
48
- has :variant, :trumps => :model
46
+ has :model, :display => lambda { |c| "Brand new #{c}" }
47
+ has :variant, :trumps => :model do
48
+ displays { |v| "Featuring #{v}" }
49
+ end
49
50
  end
50
51
  end
51
52
 
@@ -446,4 +447,12 @@ class TestCharacterizable < Test::Unit::TestCase
446
447
  assert_equal [], a.characteristics.lacking.keys
447
448
  assert_equal [], a.characteristics.trumped.keys
448
449
  end
450
+
451
+ should 'display custom formats' do
452
+ sa = SimpleAutomobile.new
453
+ sa.model = 'FIT'
454
+ assert_equal 'Brand new FIT', sa.display_characteristic(:model)
455
+ sa.variant = 'Extreme Edition'
456
+ assert_equal 'Featuring Extreme Edition', sa.display_characteristic(:variant)
457
+ end
449
458
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: characterizable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 61
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
7
+ - 1
8
8
  - 0
9
- - 17
10
- version: 0.0.17
9
+ version: 0.1.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Andy Rossmeissl
@@ -16,7 +15,7 @@ autorequire:
16
15
  bindir: bin
17
16
  cert_chain: []
18
17
 
19
- date: 2010-09-30 00:00:00 -05:00
18
+ date: 2010-11-03 00:00:00 -04:00
20
19
  default_executable:
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
@@ -27,7 +26,6 @@ dependencies:
27
26
  requirements:
28
27
  - - ">="
29
28
  - !ruby/object:Gem::Version
30
- hash: 23
31
29
  segments:
32
30
  - 0
33
31
  - 3
@@ -43,7 +41,6 @@ dependencies:
43
41
  requirements:
44
42
  - - ">="
45
43
  - !ruby/object:Gem::Version
46
- hash: 9
47
44
  segments:
48
45
  - 2
49
46
  - 3
@@ -59,7 +56,6 @@ dependencies:
59
56
  requirements:
60
57
  - - ">="
61
58
  - !ruby/object:Gem::Version
62
- hash: 3
63
59
  segments:
64
60
  - 0
65
61
  version: "0"
@@ -83,6 +79,11 @@ files:
83
79
  - VERSION
84
80
  - characterizable.gemspec
85
81
  - lib/characterizable.rb
82
+ - lib/characterizable/base.rb
83
+ - lib/characterizable/better_hash.rb
84
+ - lib/characterizable/characteristic.rb
85
+ - lib/characterizable/snapshot.rb
86
+ - test/characterizable/test_characteristic.rb
86
87
  - test/helper.rb
87
88
  - test/test_characterizable.rb
88
89
  has_rdoc: true
@@ -99,7 +100,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
100
  requirements:
100
101
  - - ">="
101
102
  - !ruby/object:Gem::Version
102
- hash: 3
103
103
  segments:
104
104
  - 0
105
105
  version: "0"
@@ -108,7 +108,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  requirements:
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
- hash: 3
112
111
  segments:
113
112
  - 0
114
113
  version: "0"
@@ -120,5 +119,6 @@ signing_key:
120
119
  specification_version: 3
121
120
  summary: Characterize instances of a class
122
121
  test_files:
122
+ - test/characterizable/test_characteristic.rb
123
123
  - test/helper.rb
124
124
  - test/test_characterizable.rb