characterizable 0.0.9 → 0.0.10

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.
@@ -4,6 +4,58 @@
4
4
 
5
5
  http://tinyurl.com/28tcrw2
6
6
 
7
+ == What is a BetterHash?
8
+
9
+ It just brings some Ruby 1.9 behavior to Ruby 1.8 hashes... (from http://webonrails.com/2009/02/06/ruby-191-hash)
10
+
11
+ RUBY_VERSION => 1.8.6
12
+ >> hash = {:a=> 1, :b=>2, :c=>3, :d=>4}
13
+ => {:b=>2, :c=>3, :d=>4, :a=>1}
14
+ >> hash.select{|k,v| k == :c }
15
+ => [[:c, 3]]
16
+
17
+ RUBY_VERSION => 1.9.1
18
+ >> hash = {:a=> 1, :b=>2, :c=>3, :d=>4}
19
+ => {:a=>1, :b=>2, :c=>3, :d=>4}
20
+ >> hash.select{|k,v| k == :c }
21
+ => {:c=>3}
22
+
23
+ I hope these two tests show the value of BetterHash in the context of this gem...
24
+
25
+ should "not be annoying to work with characteristics on a particular instance" do
26
+ a = SimpleAutomobile.new
27
+ a.make = 'Nissan'
28
+ assert_same_contents [:make], a.characteristics.effective.keys
29
+ assert_same_contents [:make], a.characteristics.effective.select { true }.keys
30
+ end
31
+
32
+ should "not be annoying to work with characteristics hashes on a class level"
33
+ assert_same_contents [:make, :model, :variant], SimpleAutomobile.characteristics.keys
34
+ assert_same_contents [:make, :model, :variant], SimpleAutomobile.characteristics.select { true }.keys
35
+ end
36
+
37
+ If you didn't have BetterHash, you wouldn't be able to call <tt>#keys</tt> because in Ruby 1.8 <tt>Hash#select</tt> (and <tt>#reject</tt>) gives you back an Array.
38
+
39
+ == What is a Snapshot?
40
+
41
+ It's a hash of the characteristics at a particular time...
42
+
43
+ should "keep snapshots separately" do
44
+ my_car = Automobile.new
45
+ my_car.make = 'Ford'
46
+ my_car.model_year = 1999
47
+ snapshot = my_car.characteristics
48
+ assert_same_contents [:make, :model_year], snapshot.effective.keys
49
+ my_car.make = nil
50
+ assert_same_contents [], my_car.characteristics.effective.keys # up to date!
51
+ assert_same_contents [:make, :model_year], snapshot.effective.keys # frozen in time!
52
+ end
53
+
54
+ There are two important points here:
55
+
56
+ * If you call <tt>my_car.characteristics</tt>, you will always get the most recent snapshot
57
+ * If you save the output to a variable like <tt>snapshot</tt>, that snapshot won't change
58
+
7
59
  == Note on Patches/Pull Requests
8
60
 
9
61
  * Fork the project.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.9
1
+ 0.0.10
@@ -1,60 +1,60 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{characterizable}
8
- s.version = "0.0.9"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Andy Rossmeissl", "Seamus Abshere"]
12
- s.date = %q{2010-07-06}
13
- s.description = %q{Characterize the relationship between "attributes" (getters/setters) of instances of a class}
14
- s.email = %q{seamus@abshere.net}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "characterizable.gemspec",
27
- "lib/characterizable.rb",
28
- "test/helper.rb",
29
- "test/test_characterizable.rb"
30
- ]
31
- s.homepage = %q{http://github.com/seamusabshere/characterizable}
32
- s.rdoc_options = ["--charset=UTF-8"]
33
- s.require_paths = ["lib"]
34
- s.rubygems_version = %q{1.3.6}
35
- s.summary = %q{Characterize instances of a class}
36
- s.test_files = [
37
- "test/helper.rb",
38
- "test/test_characterizable.rb"
39
- ]
40
-
41
- if s.respond_to? :specification_version then
42
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
- s.specification_version = 3
44
-
45
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
- s.add_runtime_dependency(%q<blockenspiel>, [">= 0.3.2"])
47
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
48
- s.add_development_dependency(%q<shoulda>, [">= 0"])
49
- else
50
- s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
51
- s.add_dependency(%q<activesupport>, [">= 2.3.5"])
52
- s.add_dependency(%q<shoulda>, [">= 0"])
53
- end
54
- else
55
- s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
56
- s.add_dependency(%q<activesupport>, [">= 2.3.5"])
57
- s.add_dependency(%q<shoulda>, [">= 0"])
58
- end
59
- end
60
-
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{characterizable}
8
+ s.version = "0.0.10"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andy Rossmeissl", "Seamus Abshere"]
12
+ s.date = %q{2010-07-06}
13
+ s.description = %q{Characterize the relationship between "attributes" (getters/setters) of instances of a class}
14
+ s.email = %q{seamus@abshere.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "characterizable.gemspec",
27
+ "lib/characterizable.rb",
28
+ "test/helper.rb",
29
+ "test/test_characterizable.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/seamusabshere/characterizable}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.7}
35
+ s.summary = %q{Characterize instances of a class}
36
+ s.test_files = [
37
+ "test/helper.rb",
38
+ "test/test_characterizable.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<blockenspiel>, [">= 0.3.2"])
47
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
48
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
49
+ else
50
+ s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
51
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
52
+ s.add_dependency(%q<shoulda>, [">= 0"])
53
+ end
54
+ else
55
+ s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
56
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
57
+ s.add_dependency(%q<shoulda>, [">= 0"])
58
+ end
59
+ end
60
+
@@ -3,6 +3,7 @@ require 'blockenspiel'
3
3
  require 'active_support'
4
4
  require 'active_support/version'
5
5
  %w{
6
+ active_support/core_ext/hash/slice
6
7
  active_support/core_ext/class/attribute_accessors
7
8
  active_support/core_ext/object/blank
8
9
  active_support/core_ext/array/wrap
@@ -26,45 +27,45 @@ module Characterizable
26
27
  @_characteristics = nil
27
28
  end
28
29
 
29
- # hashes that survive as such when you select/reject/slice them
30
- # they also keep arguments passed to them
31
- class SurvivorHash < Hash
32
- attr_reader :survivor_args
33
- def initialize(*survivor_args)
34
- @survivor_args = survivor_args
35
- end
36
- def reject(&block)
37
- inject(self.class.new(*survivor_args)) do |memo, ary|
38
- unless block.call(*ary)
39
- memo[ary[0]] = ary[1]
30
+ class BetterHash < ::Hash
31
+ # In Ruby 1.9, running select/reject/etc. gives you back a hash
32
+ if RUBY_VERSION < '1.9'
33
+ def reject(&block)
34
+ inject(Characterizable::BetterHash.new) do |memo, ary|
35
+ unless block.call(*ary)
36
+ memo[ary[0]] = ary[1]
37
+ end
38
+ memo
40
39
  end
41
- memo
42
40
  end
43
- end
44
- def select(&block)
45
- inject(self.class.new(*survivor_args)) do |memo, ary|
46
- if block.call(*ary)
47
- memo[ary[0]] = ary[1]
41
+ def select(&block)
42
+ inject(Characterizable::BetterHash.new) do |memo, ary|
43
+ if block.call(*ary)
44
+ memo[ary[0]] = ary[1]
45
+ end
46
+ memo
48
47
  end
49
- memo
50
48
  end
51
- end
52
- def slice(*keep)
53
- inject(self.class.new(*survivor_args)) do |memo, ary|
54
- if keep.include?(ary[0])
55
- memo[ary[0]] = ary[1]
49
+ # I need this because otherwise it will try to do self.class.new on subclasses
50
+ # which would get "0 for 1" arguments error with Snapshot, among other things
51
+ def slice(*keep)
52
+ inject(Characterizable::BetterHash.new) do |memo, ary|
53
+ if keep.include?(ary[0])
54
+ memo[ary[0]] = ary[1]
55
+ end
56
+ memo
56
57
  end
57
- memo
58
58
  end
59
59
  end
60
60
  end
61
61
 
62
- class Snapshot < SurvivorHash
63
- def initialize(*survivor_args)
64
- super
65
- take_snapshot
62
+ class Snapshot < BetterHash
63
+ attr_reader :target
64
+ def initialize(target)
65
+ @target = target
66
+ _take_snapshot
66
67
  end
67
- def take_snapshot
68
+ def _take_snapshot
68
69
  target.characterizable_base.characteristics.each do |_, c|
69
70
  if c.known?(target)
70
71
  if c.effective?(target)
@@ -78,16 +79,6 @@ module Characterizable
78
79
  end
79
80
  end
80
81
  end
81
- def slice(*keep)
82
- copy = self.class.new *survivor_args
83
- copy.keys.each do |key|
84
- copy.delete key unless keep.include? key
85
- end
86
- copy
87
- end
88
- def target
89
- survivor_args.first
90
- end
91
82
  def []=(key, value)
92
83
  target.expire_snapshot!
93
84
  super
@@ -132,7 +123,7 @@ module Characterizable
132
123
  @klass = klass
133
124
  end
134
125
  def characteristics
135
- @_characteristics ||= SurvivorHash.new
126
+ @_characteristics ||= BetterHash.new
136
127
  end
137
128
  include Blockenspiel::DSL
138
129
  def has(name, options = {}, &block)
@@ -62,22 +62,35 @@ class TestCharacterizable < Test::Unit::TestCase
62
62
  should "survive as a certain kind of hash" do
63
63
  a = SimpleAutomobile.new
64
64
 
65
- assert_equal Characterizable::SurvivorHash, SimpleAutomobile.characteristics.class
66
- assert_equal Characterizable::SurvivorHash, SimpleAutomobile.characteristics.select { false }.class
67
- assert_equal Characterizable::SurvivorHash, SimpleAutomobile.characteristics.slice(:hello).class
68
- assert_equal Characterizable::SurvivorHash, SimpleAutomobile.characteristics.merge({:hi => 'there'}).class
65
+ assert_equal Characterizable::BetterHash, SimpleAutomobile.characteristics.class
66
+ assert_equal Characterizable::BetterHash, SimpleAutomobile.characteristics.select { false }.class
67
+ assert_equal Characterizable::BetterHash, SimpleAutomobile.characteristics.slice(:hello).class
68
+ assert_equal Characterizable::BetterHash, SimpleAutomobile.characteristics.merge({:hi => 'there'}).class
69
69
 
70
- assert_equal Characterizable::SurvivorHash, a.characteristics.effective.class
71
- assert_equal Characterizable::SurvivorHash, a.characteristics.effective.select { false }.class
72
- assert_equal Characterizable::SurvivorHash, a.characteristics.effective.slice(:hello).class
73
- assert_equal Characterizable::SurvivorHash, a.characteristics.effective.merge({:hi => 'there'}).class
70
+ assert_equal Characterizable::BetterHash, a.characteristics.effective.class
71
+ assert_equal Characterizable::BetterHash, a.characteristics.effective.select { false }.class
72
+ assert_equal Characterizable::BetterHash, a.characteristics.effective.slice(:hello).class
73
+ assert_equal Characterizable::BetterHash, a.characteristics.effective.merge({:hi => 'there'}).class
74
+
75
+ assert_equal Characterizable::BetterHash, a.characteristics.select { false }.class
76
+ assert_equal Characterizable::BetterHash, a.characteristics.slice(:hello).class
74
77
 
75
78
  assert_equal Characterizable::Snapshot, a.characteristics.class
76
- assert_equal Characterizable::Snapshot, a.characteristics.select { false }.class
77
- assert_equal Characterizable::Snapshot, a.characteristics.slice(:hello).class
78
79
  assert_equal Characterizable::Snapshot, a.characteristics.merge({:hi => 'there'}).class
79
80
  end
80
81
 
82
+ should "not be annoying to work with characteristics on a particular instance" do
83
+ a = SimpleAutomobile.new
84
+ a.make = 'Nissan'
85
+ assert_same_contents [:make], a.characteristics.effective.keys
86
+ assert_same_contents [:make], a.characteristics.effective.select { true }.keys
87
+ end
88
+
89
+ should "not be annoying to work with characteristics hashes on a class level" do
90
+ assert_same_contents [:make, :model, :variant], SimpleAutomobile.characteristics.keys
91
+ assert_same_contents [:make, :model, :variant], SimpleAutomobile.characteristics.select { true }.keys
92
+ end
93
+
81
94
  should "tell you what characteristics are effective" do
82
95
  a = SimpleAutomobile.new
83
96
  a.make = 'Ford'
@@ -229,8 +242,8 @@ class TestCharacterizable < Test::Unit::TestCase
229
242
  snapshot = a.characteristics
230
243
  assert_same_contents [:make, :model_year], snapshot.effective.keys
231
244
  a.make = nil
232
- assert_same_contents [], a.characteristics.effective.keys
233
- assert_same_contents [:make, :model_year], snapshot.effective.keys
245
+ assert_same_contents [], a.characteristics.effective.keys # up to date!
246
+ assert_same_contents [:make, :model_year], snapshot.effective.keys # frozen in time!
234
247
  end
235
248
 
236
249
  should "work when passed around as a snapshot" do
@@ -323,5 +336,31 @@ class TestCharacterizable < Test::Unit::TestCase
323
336
  a.make = 'Ford'
324
337
  assert_equal({ :make => 'Ford' }, a.characteristics)
325
338
  assert_equal({}, a.characteristics.slice(:dummy))
339
+ assert_equal({ :make => 'Ford' }, a.characteristics.slice(:make))
340
+ end
341
+
342
+ should 'allow characterizations to be selected' do
343
+ a = Automobile.new
344
+ a.make = 'Ford'
345
+ assert_equal({ :make => 'Ford' }, a.characteristics.select { |k, v| k == :make })
346
+ assert_equal({}, a.characteristics.select { |k, v| k == :dummy })
347
+ end
348
+
349
+ should 'allow characterizations to be rejected' do
350
+ a = Automobile.new
351
+ a.make = 'Ford'
352
+ assert_equal({ :make => 'Ford' }, a.characteristics.reject { |k, v| k == :dummy })
353
+ assert_equal({}, a.characteristics.reject { |k, v| k == :make })
326
354
  end
355
+
356
+ should 'not reset snapshot after slicing' do
357
+ a = Automobile.new
358
+ a.make = 'Ford'
359
+ snapshot = a.characteristics.slice(:dummy)
360
+ assert_equal({}, snapshot)
361
+ a.make = 'Nissan'
362
+ assert_equal({}, snapshot)
363
+ assert_equal({}, snapshot.slice(:make))
364
+ end
365
+
327
366
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: characterizable
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 11
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 0
8
- - 9
9
- version: 0.0.9
9
+ - 10
10
+ version: 0.0.10
10
11
  platform: ruby
11
12
  authors:
12
13
  - Andy Rossmeissl
@@ -22,9 +23,11 @@ dependencies:
22
23
  name: blockenspiel
23
24
  prerelease: false
24
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
25
27
  requirements:
26
28
  - - ">="
27
29
  - !ruby/object:Gem::Version
30
+ hash: 23
28
31
  segments:
29
32
  - 0
30
33
  - 3
@@ -36,9 +39,11 @@ dependencies:
36
39
  name: activesupport
37
40
  prerelease: false
38
41
  requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
39
43
  requirements:
40
44
  - - ">="
41
45
  - !ruby/object:Gem::Version
46
+ hash: 9
42
47
  segments:
43
48
  - 2
44
49
  - 3
@@ -50,9 +55,11 @@ dependencies:
50
55
  name: shoulda
51
56
  prerelease: false
52
57
  requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
53
59
  requirements:
54
60
  - - ">="
55
61
  - !ruby/object:Gem::Version
62
+ hash: 3
56
63
  segments:
57
64
  - 0
58
65
  version: "0"
@@ -88,23 +95,27 @@ rdoc_options:
88
95
  require_paths:
89
96
  - lib
90
97
  required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
91
99
  requirements:
92
100
  - - ">="
93
101
  - !ruby/object:Gem::Version
102
+ hash: 3
94
103
  segments:
95
104
  - 0
96
105
  version: "0"
97
106
  required_rubygems_version: !ruby/object:Gem::Requirement
107
+ none: false
98
108
  requirements:
99
109
  - - ">="
100
110
  - !ruby/object:Gem::Version
111
+ hash: 3
101
112
  segments:
102
113
  - 0
103
114
  version: "0"
104
115
  requirements: []
105
116
 
106
117
  rubyforge_project:
107
- rubygems_version: 1.3.6
118
+ rubygems_version: 1.3.7
108
119
  signing_key:
109
120
  specification_version: 3
110
121
  summary: Characterize instances of a class