characterizable 0.0.17 → 0.1.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.
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