using_yaml 1.1.0 → 1.1.1

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.
@@ -82,6 +82,33 @@ By default, UsingYAML will return nil for missing files. It will also complain o
82
82
 
83
83
  UsingYAML.squelch!
84
84
 
85
+ == Benchmark
86
+
87
+ There are two extremes when navigating hashes. Either we hit a nil
88
+ early, or we traverse successfully to the end. UsingYAML performs well regardless. Here are results using `ruby-1.8.7-p249 [ x86_64 ]`
89
+
90
+ === Testing chains of nils
91
+
92
+ user system total real
93
+ normal 0.920000 0.040000 0.960000 ( 0.980095)
94
+ chained 0.900000 0.060000 0.960000 ( 0.973219)
95
+
96
+ === Testing where the keys exist
97
+
98
+ user system total real
99
+ normal 2.780000 0.150000 2.930000 ( 2.930808)
100
+ chained 0.960000 0.060000 1.020000 ( 1.031477)
101
+
102
+ === Results
103
+
104
+ While there are certainly other things to test, these benchmarks show
105
+ that the method chaining performs either almost as well (in the case
106
+ of nil.nil..) or significantly better (in the case of key.key..).
107
+
108
+ I'd definitely like to do some more testing. However, this is
109
+ primarily a convenience library to improve programmer happiness, so
110
+ these tests have made me happy enough for now.
111
+
85
112
  == Note on Patches/Pull Requests
86
113
 
87
114
  * Fork the project.
data/Rakefile CHANGED
@@ -51,6 +51,15 @@ task :benchmark do
51
51
  p = Person.new
52
52
  p.children # "cache" the nil
53
53
  n = 10000
54
+
55
+ puts "** Testing chains of nils **"
56
+ Benchmark.bmbm(10) do |x|
57
+ x.report("normal") { n.times do; p.children && p.children['something'] && p.children['invalid']; end }
58
+ x.report("chained") { n.times do; p.children.something.invalid; end }
59
+ end
60
+
61
+ p.children = { 'something' => { 'valid' => 1 } }
62
+ puts "\n** Testing where the keys exist **"
54
63
  Benchmark.bmbm(10) do |x|
55
64
  x.report("normal") { n.times do; p.children && p.children['something'] && p.children['invalid']; end }
56
65
  x.report("chained") { n.times do; p.children.something.invalid; end }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.1.1
@@ -22,7 +22,12 @@ end
22
22
  #
23
23
  # See +using_yaml+ for usage information.
24
24
  module UsingYAML
25
- NilClass = add_nilclass_extensions(nil, nil)
25
+ NilExt = Module.new do
26
+ define_method(:method_missing) do |*args|
27
+ self
28
+ end
29
+ end
30
+ NilClass = nil.extend(NilExt)
26
31
 
27
32
  class << self
28
33
  # Extends the incoming Array/Hash with magic which makes it
@@ -35,11 +40,7 @@ module UsingYAML
35
40
  when Hash
36
41
  add_hash_extensions(object, pathname)
37
42
  when ::NilClass
38
- if pathname
39
- add_nilclass_extensions(object, pathname)
40
- else
41
- UsingYAML::NilClass
42
- end
43
+ UsingYAML::NilClass
43
44
  end
44
45
 
45
46
  object
@@ -2,29 +2,22 @@ module UsingYAML
2
2
  # Calls add_extensions on all children. Also defines a +save+ method
3
3
  # iff this is a top-level UsingYAML object (see below for details).
4
4
  def self.add_array_extensions(array, pathname)
5
- # Here we define a Module to extend the array
6
- extensions = Module.new do
7
- # Iterate over the items
8
- array.each do |item|
9
- # Recursively continue to extend.
10
- UsingYAML.add_extensions(item)
11
- end
12
-
13
- # Define a save method if a pathname was supplied (only happens
14
- # on the top-level object - that is, example.foo will have a
15
- # +save+, but example.foo.bar will not).
16
- if pathname
17
- define_method(:save) do
18
- # Serialise using +to_yaml+
19
- File.open(pathname, 'w') do |f|
20
- f.puts self.to_yaml
21
- end
22
- end
23
- end
5
+ # Iterate over the items
6
+ array.each do |item|
7
+ # Recursively continue to extend.
8
+ UsingYAML.add_extensions(item)
24
9
  end
25
-
10
+
26
11
  # Load in the extensions for this instance
27
- array.extend(extensions)
12
+ array.instance_eval <<-RUBY
13
+ def save
14
+ # Serialise using +to_yaml+
15
+ File.open("#{pathname}", 'w') do |f|
16
+ f.puts self.to_yaml
17
+ end
18
+ end
19
+ RUBY
20
+
28
21
  array
29
22
  end
30
23
  end
@@ -2,14 +2,13 @@ module UsingYAML
2
2
  # Calls add_extensions on all children. Also defines a +save+ method
3
3
  # iff this is a top-level UsingYAML object (see below for details).
4
4
  def self.add_hash_extensions(hash, pathname)
5
- # Here we define a Module to extend the hash
6
- extensions = Module.new do
7
- # Recursively continue to extend.
8
- hash.each_pair do |key, value|
9
- UsingYAML.add_extensions(value)
10
- end
5
+ # Recursively continue to extend.
6
+ hash.each_pair do |key, value|
7
+ UsingYAML.add_extensions(value)
8
+ end
11
9
 
12
- define_method(:method_missing) do |*args|
10
+ hash.instance_eval <<-RUBY
11
+ def method_missing(*args)
13
12
  name = args.shift.to_s
14
13
 
15
14
  if args.empty?
@@ -21,39 +20,30 @@ module UsingYAML
21
20
  # consistently with the other key-value pairs.
22
21
  key = $1
23
22
  value = args.first
24
-
23
+
25
24
  # Save the value in the hashtable
26
25
  send(:[]=, key, UsingYAML.add_extensions(value))
27
-
28
- # Define the new reader (as above)
29
- new_reader_extension = Module.new do
30
- define_method(key) do
31
- send(:[], key) || UsingYAML.add_extensions(nil)
32
- end
33
- end
34
- extend(new_reader_extension)
35
-
36
26
  value
37
27
  else
38
28
  super(name, args)
39
29
  end
40
30
  end
31
+ RUBY
41
32
 
42
- # Define a save method if a pathname was supplied (only happens
43
- # on the top-level object - that is, example.foo will have a
44
- # +save+, but example.foo.bar will not).
45
- if pathname
46
- define_method(:save) do
33
+ # Define a save method if a pathname was supplied (only happens
34
+ # on the top-level object - that is, example.foo will have a
35
+ # +save+, but example.foo.bar will not).
36
+ if pathname
37
+ hash.instance_eval <<-RUBY
38
+ def save
47
39
  # Serialise using +to_yaml+
48
- File.open(pathname, 'w') do |f|
40
+ File.open("#{pathname}", 'w') do |f|
49
41
  f.puts self.to_yaml
50
42
  end
51
43
  end
52
- end
44
+ RUBY
53
45
  end
54
-
55
- # Load in the extensions for this instance
56
- hash.extend(extensions)
46
+
57
47
  hash
58
48
  end
59
49
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{using_yaml}
8
- s.version = "1.1.0"
8
+ s.version = "1.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Marc Bowes"]
12
- s.date = %q{2010-03-30}
12
+ s.date = %q{2010-04-21}
13
13
  s.description = %q{"Load, save and use YAML files as if they were objects"}
14
14
  s.email = %q{marcbowes@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -26,7 +26,6 @@ Gem::Specification.new do |s|
26
26
  "lib/using_yaml.rb",
27
27
  "lib/using_yaml/array.rb",
28
28
  "lib/using_yaml/hash.rb",
29
- "lib/using_yaml/nilclass.rb",
30
29
  "spec/spec_helper.rb",
31
30
  "spec/using_yaml/path_spec.rb",
32
31
  "spec/using_yaml/using_yaml_spec.rb",
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 1
8
- - 0
9
- version: 1.1.0
8
+ - 1
9
+ version: 1.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Marc Bowes
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-30 00:00:00 +02:00
17
+ date: 2010-04-21 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -48,7 +48,6 @@ files:
48
48
  - lib/using_yaml.rb
49
49
  - lib/using_yaml/array.rb
50
50
  - lib/using_yaml/hash.rb
51
- - lib/using_yaml/nilclass.rb
52
51
  - spec/spec_helper.rb
53
52
  - spec/using_yaml/path_spec.rb
54
53
  - spec/using_yaml/using_yaml_spec.rb
@@ -1,34 +0,0 @@
1
- module UsingYAML
2
- def self.add_nilclass_extensions(instance, pathname)
3
- extensions = Module.new do
4
- define_method(:method_missing) do |*args|
5
- # Child objects should not have #save
6
- if respond_to? :save
7
- UsingYAML::NilClass
8
- else
9
- # One nil is the same as the next :)
10
- self
11
- end
12
- end
13
-
14
- # Define a save method if a pathname was supplied (only happens
15
- # on the top-level object - that is, example.foo will have a
16
- # +save+, but example.foo.bar will not).
17
- if pathname
18
- # Being nil translates to "no file", not to "empty file", so we
19
- # want to actually delete any existing file. This is a semantic
20
- # difference, but important: there is a huge different between
21
- # an _empty_ file and a _non-existant_ file. YAML does not
22
- # reflect this difference, so we do.
23
- define_method(:save) do
24
- # If we can't delete it (permissions, ENOENT..), then there
25
- # ain't much we can do, so just squelch the error.
26
- FileUtils.rm(pathname) rescue nil
27
- end
28
- end
29
- end
30
-
31
- instance.extend(extensions)
32
- instance
33
- end
34
- end