characterizable 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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