yamldoc 0.0.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.
- data/.gitignore +9 -0
- data/CHANGELOG.rdoc +27 -0
- data/LICENSE +21 -0
- data/README.rdoc +98 -0
- data/Rakefile +33 -0
- data/VERSION.yml +4 -0
- data/init.rb +1 -0
- data/lib/class_attributes.rb +128 -0
- data/lib/yamldoc.rb +264 -0
- data/rails/init.rb +1 -0
- data/spec/examples_unsorted.rb +219 -0
- data/spec/settings.rb +3 -0
- data/spec/settings.yml +16 -0
- data/spec/settings2.rb +4 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/yamldoc_spec.rb +36 -0
- data/yamldoc.gemspec +60 -0
- metadata +76 -0
data/.gitignore
ADDED
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
== 2.0.2 released 2009-08-22
|
2
|
+
|
3
|
+
* Define methods during method_missing instead of during initialization. Allows for modification on the fly.
|
4
|
+
|
5
|
+
== 2.0.0 released 2009-08-22
|
6
|
+
|
7
|
+
* Less magic, instead of automatically defining a Settings constant, you should define your own constant. See the readme for an example.
|
8
|
+
|
9
|
+
== 1.0.3 released 2009-04-23
|
10
|
+
|
11
|
+
* Fix Settings initialized with a Hash to work with both symbol and string hash keys.
|
12
|
+
|
13
|
+
== 1.0.2 released 2009-04-09
|
14
|
+
|
15
|
+
* Call key? off of the self in the class level name method.
|
16
|
+
|
17
|
+
== 1.0.1 released 2009-04-02
|
18
|
+
|
19
|
+
* Inherit from hash.
|
20
|
+
|
21
|
+
== 1.0.0 released 2008-12-05
|
22
|
+
|
23
|
+
* Only define methods if we have settings.
|
24
|
+
|
25
|
+
== 0.9.0 released 2008-10-30
|
26
|
+
|
27
|
+
* Initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2009 dreamcat4
|
2
|
+
Copyright (c) 2008 Ben Johnson of Binary Logic (binarylogic.com)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
= YamlDoc
|
2
|
+
|
3
|
+
YamlDoc is a simple Yaml reader/writer solution that uses an ERB enabled YAML file. Yaml is represented as a Hash tree. Features include
|
4
|
+
|
5
|
+
Autosave, object detection (modified in-place). Force uniform hash keys as String or Sym, dot notation for nested objects, and manual write for large files.
|
6
|
+
|
7
|
+
== Install
|
8
|
+
|
9
|
+
Install from gemcutter:
|
10
|
+
|
11
|
+
gem install yamldoc
|
12
|
+
|
13
|
+
== Quickstart
|
14
|
+
|
15
|
+
There are various ways to create
|
16
|
+
|
17
|
+
class Settings < YamlDoc
|
18
|
+
self.filename = "file.yml"
|
19
|
+
self.autosave = true
|
20
|
+
...
|
21
|
+
end
|
22
|
+
file = Settings.new
|
23
|
+
|
24
|
+
Or
|
25
|
+
|
26
|
+
settings = YamlDoc.new("file.yml")
|
27
|
+
|
28
|
+
Or
|
29
|
+
|
30
|
+
settings = YamlDoc.new :filename => "file.yml", :autosave => true
|
31
|
+
|
32
|
+
== YmlDoc Methods
|
33
|
+
|
34
|
+
In most cases the `:save` method is all you will need.
|
35
|
+
|
36
|
+
config.methods.inspect
|
37
|
+
=> [:load, :save, :methods, :properties, :reload_hooks]
|
38
|
+
|
39
|
+
`:load` will reload the existing file, or (with a parameter) merge the existing object into the newly loaded file (and re-save it). So generally use `YamlDoc.new` to load a different file.
|
40
|
+
|
41
|
+
== YmlDoc Properties
|
42
|
+
|
43
|
+
YamlDoc.defaults.inspect
|
44
|
+
=> {:ymldoc_pfx=>"", :deep_clone=>false, :force_keys=>false, :key_type=>String, :autosave=>false, :object_detection=>false, :filename=>nil}
|
45
|
+
|
46
|
+
== AutoYamlDoc Class
|
47
|
+
|
48
|
+
Of course it's tempting to just turn everything on for easy access to yml settings file. So we've gone ahead and created an "everythin on" class.
|
49
|
+
|
50
|
+
AutoYamlDoc.defaults.inspect
|
51
|
+
=> {:ymldoc_pfx=>"", :deep_clone=>false, :force_keys=>true, :key_type=>String, :autosave=>true, :object_detection=>true, :filename=>nil}
|
52
|
+
|
53
|
+
AutoYmlDoc.new("settings.yml")
|
54
|
+
|
55
|
+
== Object Manipulation
|
56
|
+
|
57
|
+
The deserialized Yaml object just a special kind of nested hash.
|
58
|
+
|
59
|
+
settings.a = "Somestring"
|
60
|
+
settings.b = [:label1,:label2,:label3]
|
61
|
+
settings.b[1].inspect
|
62
|
+
=> :label2
|
63
|
+
|
64
|
+
settings.defaults.d = { "key1" => "val1", ... }
|
65
|
+
settings.defaults.key1
|
66
|
+
=> "val1"
|
67
|
+
|
68
|
+
other_hash = { "key1" => 5 }
|
69
|
+
settings.merge! other_hash
|
70
|
+
settings.key1
|
71
|
+
=> 5
|
72
|
+
|
73
|
+
== Advanced yamldoc methods and properties
|
74
|
+
|
75
|
+
config.methods.inspect
|
76
|
+
=> [:load, :save, :methods, :properties, :reload_hooks]
|
77
|
+
|
78
|
+
You can rename the standard YmlDoc methods by setting the :ymldoc_pfx property. This is useful should any namespace clashes occur at the root (topmost) level of your yaml file. For example if we encountered a yaml file which has topmost nodes `save` and `:filename`. These are part of the YamlDoc API methods. So we use a `:ymldoc_pfx` to rename the YmlDoc object methods to something else. For example:
|
79
|
+
|
80
|
+
config.properties.inspect
|
81
|
+
=> [:object_detection, :root_obj, :ymldoc_pfx, :force_keys, :deep_clone, :detection_hooks, :key_type, :autosave, :filename]
|
82
|
+
|
83
|
+
config.ymldoc_pfx = "yml_"
|
84
|
+
config.reload_hooks
|
85
|
+
config.yml_methods.inspect
|
86
|
+
=> [:yml_load, :yml_save, :yml_methods, :yml_properties, :yml_reload_hooks]
|
87
|
+
|
88
|
+
config.save = "somestring"
|
89
|
+
config.save
|
90
|
+
=> "somestring"
|
91
|
+
|
92
|
+
config.yml_save()
|
93
|
+
# file saved.
|
94
|
+
|
95
|
+
== Copyright, License
|
96
|
+
|
97
|
+
Copyright (c) 2009 dreamcat4
|
98
|
+
Copyright (c) 2008 {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com], released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "yamldoc"
|
8
|
+
gem.summary = "A simple solution for ERB enabled YAML file."
|
9
|
+
gem.email = "dreamcat4@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/dreamcat4/yamldoc"
|
11
|
+
gem.authors = ["dreamcat4, Ben Johnson"]
|
12
|
+
gem.rubyforge_project = ""
|
13
|
+
end
|
14
|
+
Jeweler::RubyforgeTasks.new
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'spec/rake/spectask'
|
20
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
21
|
+
spec.libs << 'lib' << 'spec'
|
22
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
23
|
+
end
|
24
|
+
|
25
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
26
|
+
spec.libs << 'lib' << 'spec'
|
27
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
28
|
+
spec.rcov = true
|
29
|
+
end
|
30
|
+
|
31
|
+
task :spec => :check_dependencies
|
32
|
+
|
33
|
+
task :default => :spec
|
data/VERSION.yml
ADDED
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init.rb"
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# class_attributes.rb - Class Attributes
|
2
|
+
# A Feature-complete alternative to @@
|
3
|
+
|
4
|
+
class Object
|
5
|
+
def deep_clone; Marshal::load(Marshal.dump(self)); end
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassAttributes
|
9
|
+
|
10
|
+
def cattr(*args, &block)
|
11
|
+
(class << self; self; end).class_eval do
|
12
|
+
attr_accessor *args
|
13
|
+
end
|
14
|
+
@cattr ||= []
|
15
|
+
@cattr.concat(args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def iattr(*args, &block)
|
19
|
+
(class << self; self; end).class_eval do
|
20
|
+
attr_accessor *args
|
21
|
+
end
|
22
|
+
@iattr ||= []
|
23
|
+
@iattr.concat(args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def oattr(*args, &block)
|
27
|
+
(class << self; self; end).class_eval do
|
28
|
+
attr_accessor *args
|
29
|
+
end
|
30
|
+
@oattr ||= []
|
31
|
+
@oattr.concat(args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def oattr_i(*args, &block)
|
35
|
+
(class << self; self; end).class_eval do
|
36
|
+
attr_accessor *args
|
37
|
+
end
|
38
|
+
@oattr_i ||= []
|
39
|
+
@oattr_i.concat(args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def co_attr(*args, &block)
|
43
|
+
cattr(*args,&block)
|
44
|
+
oattr(*args,&block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def co_attr_i(*args, &block)
|
48
|
+
iattr(*args,&block)
|
49
|
+
oattr_i(*args,&block)
|
50
|
+
end
|
51
|
+
|
52
|
+
alias_method :class_inherited_attribute_shared, :cattr
|
53
|
+
alias_method :class_inherited_attribute_independant, :iattr
|
54
|
+
|
55
|
+
alias_method :object_inherited_attribute_shared, :oattr
|
56
|
+
alias_method :object_inherited_attribute_independant, :oattr_i
|
57
|
+
|
58
|
+
alias_method :class_and_object_shared_inherited_attribute, :co_attr
|
59
|
+
alias_method :class_and_object_independant_inherited_attribute, :co_attr_i
|
60
|
+
|
61
|
+
def inherited(subclass)
|
62
|
+
super(subclass) if respond_to?('super')
|
63
|
+
iattr.each do |a|
|
64
|
+
# puts "a=#{a}"
|
65
|
+
subclass.send("#{a}=", send(a).deep_clone)
|
66
|
+
subclass.send("iattr", a.to_sym)
|
67
|
+
end
|
68
|
+
cattr.each do |a|
|
69
|
+
subclass.send("#{a}=", send(a))
|
70
|
+
subclass.send("cattr", a.to_sym)
|
71
|
+
end
|
72
|
+
oattr.each do |a|
|
73
|
+
subclass.send("oattr", a.to_sym)
|
74
|
+
end
|
75
|
+
oattr_i.each do |a|
|
76
|
+
subclass.send("oattr_i", a.to_sym)
|
77
|
+
end
|
78
|
+
subclass.send(:inherit) if subclass.respond_to?('inherit')
|
79
|
+
end
|
80
|
+
|
81
|
+
def inherit(*args, &block)
|
82
|
+
super if respond_to?('super')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module ObjectPreInitialize
|
87
|
+
private
|
88
|
+
def pre_initialize(*args, &block)
|
89
|
+
super if respond_to?('super')
|
90
|
+
|
91
|
+
class_attrs = self.class.cattr + self.class.iattr
|
92
|
+
|
93
|
+
self.class.oattr.each do |a|
|
94
|
+
sac = self.class.send(a)
|
95
|
+
eval "@#{a.to_s}=sac" if class_attrs.include? a
|
96
|
+
end
|
97
|
+
|
98
|
+
self.class.oattr_i.each do |a|
|
99
|
+
sac = self.class.send(a)
|
100
|
+
eval "@#{a.to_s}=sac.deep_clone" if class_attrs.include? a
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# def postinitialize(*args, &block)
|
105
|
+
# end
|
106
|
+
end
|
107
|
+
|
108
|
+
module OverloadNew
|
109
|
+
def new(*args, &block)
|
110
|
+
newObj = self.allocate
|
111
|
+
newObj.send :extend, ObjectPreInitialize
|
112
|
+
newObj.send :pre_initialize, *args, &block
|
113
|
+
newObj.send :initialize, *args, &block
|
114
|
+
# newObj.send :postinitialize, *args, &block
|
115
|
+
return newObj
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def has_class_attributes
|
120
|
+
extend ClassAttributes
|
121
|
+
end
|
122
|
+
|
123
|
+
def has_class_object_attributes
|
124
|
+
extend ClassAttributes
|
125
|
+
extend OverloadNew
|
126
|
+
end
|
127
|
+
|
128
|
+
|
data/lib/yamldoc.rb
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "erb"
|
3
|
+
require "class_attributes"
|
4
|
+
|
5
|
+
class Object
|
6
|
+
def to_yaml_properties; instance_variables - ["@_","@_ro","@_yp","@_ym","@_as"]; end
|
7
|
+
def deep_clone; Marshal::load(Marshal.dump(self)); end
|
8
|
+
end
|
9
|
+
|
10
|
+
class YamlDoc < Hash
|
11
|
+
private
|
12
|
+
has_class_object_attributes; co_attr_i :_
|
13
|
+
|
14
|
+
@_ = {
|
15
|
+
:filename => nil,
|
16
|
+
:key_type => String,
|
17
|
+
:force_keys => false,
|
18
|
+
:object_detection => false,
|
19
|
+
:autosave => false,
|
20
|
+
:deep_clone => false,
|
21
|
+
:ymldoc_pfx => ""
|
22
|
+
}
|
23
|
+
|
24
|
+
def self.properties ; @_ ; end
|
25
|
+
|
26
|
+
def self.inherit(*args, &block)
|
27
|
+
# define class accessors for @_ (properties)
|
28
|
+
@_.keys.each do |sym|
|
29
|
+
getter = sym
|
30
|
+
self.class.send(:define_method, getter) { @_[sym] }
|
31
|
+
setter = (sym.to_s+"=").to_sym
|
32
|
+
self.class.send(:define_method, setter) { |val| @_[sym] = val }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(*args, &block)
|
37
|
+
@_ro = self
|
38
|
+
self.send(:reload_hooks)
|
39
|
+
|
40
|
+
case args.first
|
41
|
+
when String
|
42
|
+
@_[:filename] = args.first
|
43
|
+
when Hash
|
44
|
+
@_.merge! args.first
|
45
|
+
when nil
|
46
|
+
;;
|
47
|
+
else
|
48
|
+
args.each do |obj|
|
49
|
+
self["#{obj.class.inspect}"] ||= []
|
50
|
+
self["#{obj.class.inspect}"] << obj
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
load()
|
55
|
+
save(&block) if block_given?
|
56
|
+
end
|
57
|
+
|
58
|
+
def load(file=nil)
|
59
|
+
f = file || @_[:filename]
|
60
|
+
if f
|
61
|
+
if File.exists? f
|
62
|
+
yaml = YAML.load(ERB.new(File.read(f)).result)
|
63
|
+
hash = yaml.to_hash if yaml
|
64
|
+
puts yaml if yaml
|
65
|
+
end
|
66
|
+
|
67
|
+
hash = Hash.new if hash.nil?
|
68
|
+
self.merge! hash
|
69
|
+
@_[:filename] = f
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def save(&block)
|
74
|
+
# always disable autosave for effecient write
|
75
|
+
@_as = @_[:autosave] ; @_[:autosave] = false
|
76
|
+
_call_block(block) if block_given?
|
77
|
+
@_[:autosave] = @_as ; _write_file
|
78
|
+
end
|
79
|
+
|
80
|
+
def _call_block(block)
|
81
|
+
if block.arity == 1
|
82
|
+
block.call(self)
|
83
|
+
else
|
84
|
+
raise "Wrong number of arguments (#{block.arity}). This block takes 1 argument"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def properties ; @_ ; end
|
89
|
+
|
90
|
+
def methods ; @_ym ; end
|
91
|
+
|
92
|
+
def reload_hooks
|
93
|
+
pfx = @_[:ymldoc_pfx].to_s
|
94
|
+
|
95
|
+
old_props = @_yp || [] ; @_yp = []
|
96
|
+
old_props.each do |sym|
|
97
|
+
self.class.send(:remove_method,sym)
|
98
|
+
end
|
99
|
+
|
100
|
+
@_.keys.each do |sym|
|
101
|
+
getter = (pfx+sym.to_s).to_sym
|
102
|
+
self.class.send(:define_method, getter) { @_[sym] }
|
103
|
+
@_yp << getter
|
104
|
+
|
105
|
+
setter = (pfx+sym.to_s+"=").to_sym
|
106
|
+
self.class.send(:define_method, setter) { |val| @_[sym] = val }
|
107
|
+
end
|
108
|
+
|
109
|
+
old_methods = @_ym || [] ; @_ym = []
|
110
|
+
old_methods.each do |sym|
|
111
|
+
self.class.send(:remove_method,sym)
|
112
|
+
end
|
113
|
+
|
114
|
+
[:load, :save, :methods, :properties, :reload_hooks].each do |sym|
|
115
|
+
m = (pfx+sym.to_s).to_sym
|
116
|
+
self.class.send(:define_method, m, self.method(sym))
|
117
|
+
@_ym << m
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
module HashChanged
|
122
|
+
def self.object_changed_methods(obj=nil)
|
123
|
+
hash_keys_method = [:[]=]
|
124
|
+
[:[]=,:clear,:default=,:delete,:delete_if,:merge!,:rehash,:reject,
|
125
|
+
:reject!,:replace,:shift,:store,:update] - hash_keys_method
|
126
|
+
end
|
127
|
+
end
|
128
|
+
module ArrayChanged
|
129
|
+
def self.object_changed_methods(obj=nil)
|
130
|
+
[:<<,:[]=,:clear,:collect!,:compact!,:delete,:delete_at,:delete_if,
|
131
|
+
:fill,:flatten!,:insert,:map!,:pop,:push,:reject!,:replace,:reverse!,
|
132
|
+
:shift,:slice!,:sort!,:transpose,:uniq!,:unshift]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
module StringChanged
|
136
|
+
def self.object_changed_methods(obj=nil)
|
137
|
+
[:<<,:[]=,:capitalize,:chomp!,:chop!,:concat,:delete!,:downcase!,:gsub!,
|
138
|
+
:insert,:lstrip!,:next!,:replace,:reverse!,:rstrip!,:slice!,:squeeze!,
|
139
|
+
:strip!,:sub!,:succ!,:swapcase!,:tr!,:tr_s!,:upcase!]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
module ObjectChanged
|
143
|
+
def self.object_changed_methods(obj)
|
144
|
+
obj.instance_variables.map { |s| s.delete("@")+"=" }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
module ChangedHook
|
148
|
+
def self.extended(base)
|
149
|
+
override_obj_changed_methods base
|
150
|
+
end
|
151
|
+
private
|
152
|
+
def self.override_obj_changed_methods(obj)
|
153
|
+
eigen_class = self
|
154
|
+
obj_class = obj.class.to_s.match("Hash|Array|String") || "Object"
|
155
|
+
m = eval "#{obj_class}Changed::object_changed_methods obj"
|
156
|
+
m.each do |method|
|
157
|
+
eigen_class.send(:define_method, method) {
|
158
|
+
result = super
|
159
|
+
# eval "puts \"__obj_changed_hook #{method}\""
|
160
|
+
__obj_changed_hook
|
161
|
+
return result
|
162
|
+
}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
module HashMethods
|
167
|
+
def self.extended(hash)
|
168
|
+
sanitize_hashes_recursive(hash) if hash.instance_eval{@_}[:force_keys]
|
169
|
+
end
|
170
|
+
|
171
|
+
def []=(name, *args, &block)
|
172
|
+
if @_[:force_keys]
|
173
|
+
name = name.to_s if name.class == Symbol && @_[:key_type] == String
|
174
|
+
name = name.to_sym if name.class == String && @_[:key_type] == Symbol
|
175
|
+
end
|
176
|
+
result = super
|
177
|
+
__obj_changed_hook
|
178
|
+
return result
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
def self.sanitize_hashes_recursive(hash)
|
183
|
+
if hash.instance_eval{@_}[:key_type] == String; force_class = Symbol ; conv = "to_s" ; end
|
184
|
+
if hash.instance_eval{@_}[:key_type] == Symbol; force_class = String ; conv = "to_sym" ; end
|
185
|
+
|
186
|
+
hash.each do |k,v|
|
187
|
+
if v.class == Hash; sanitize_hashes_recursive(v) ; break; end
|
188
|
+
target = eval "k.#{conv}"
|
189
|
+
if force_class == k.class && ! hash.include?(target) ; hash.store(target,v); end
|
190
|
+
end
|
191
|
+
hash.delete_if { |k,v| force_class == k.class }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
module EigenMethodDefiner # :nodoc:
|
195
|
+
private
|
196
|
+
def method_missing(name, *args, &block)
|
197
|
+
value = nil
|
198
|
+
str_full = name.to_s
|
199
|
+
str = str_full.match("=$") ? str_full.chop : str_full
|
200
|
+
sym = str.to_sym
|
201
|
+
|
202
|
+
s = @_[:key_type] == Symbol ? "sym" : "str"
|
203
|
+
eval "define_eigen_method_#{s}(#{s})"
|
204
|
+
|
205
|
+
if str_full.match "=$"
|
206
|
+
obj = args.first
|
207
|
+
obj = Hash.new if obj.nil?
|
208
|
+
value = @_[:deep_clone] ? obj.deep_clone : obj
|
209
|
+
eval "self[#{s}] = value"
|
210
|
+
else
|
211
|
+
eval "value = self[#{s}] = self[#{s}].nil? ? Hash.new : self[#{s}]"
|
212
|
+
end
|
213
|
+
|
214
|
+
yaml_types = [Hash, Array, String, Object]
|
215
|
+
yaml_types.each do |yaml_type|
|
216
|
+
if value.is_a?(yaml_type)
|
217
|
+
value.extend(EigenMethodDefiner)
|
218
|
+
parent_opts = @_
|
219
|
+
value.instance_eval { @_ = parent_opts }
|
220
|
+
root_obj = @_ro
|
221
|
+
value.instance_eval { @_ro = root_obj }
|
222
|
+
value.extend YamlDoc::ChangedHook if @_[:object_detection]
|
223
|
+
value.extend(HashMethods) if value.is_a?(Hash)
|
224
|
+
break
|
225
|
+
end
|
226
|
+
end
|
227
|
+
value
|
228
|
+
end
|
229
|
+
|
230
|
+
def __obj_changed_hook
|
231
|
+
_write_file if @_[:autosave]
|
232
|
+
end
|
233
|
+
|
234
|
+
def _write_file
|
235
|
+
if @_[:filename]
|
236
|
+
File.open(@_[:filename], 'w') do |output|
|
237
|
+
output.puts YAML.dump(@_ro)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def define_eigen_method_sym(sym)
|
243
|
+
eigen_class = class << self; self; end
|
244
|
+
eigen_class.send(:define_method, sym) { self[sym] }
|
245
|
+
eigen_class.send(:define_method, (sym.to_s+'=').to_sym) { |val| self[sym] = val }
|
246
|
+
end
|
247
|
+
def define_eigen_method_str(str)
|
248
|
+
eigen_class = class << self; self; end
|
249
|
+
eigen_class.send(:define_method, str.to_sym) { self[str] }
|
250
|
+
eigen_class.send(:define_method, (str+'=').to_sym) { |val| self[str] = val }
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
include EigenMethodDefiner
|
255
|
+
end
|
256
|
+
|
257
|
+
class AutoYamlDoc < YamlDoc
|
258
|
+
self.force_keys = true
|
259
|
+
self.object_detection = true
|
260
|
+
self.autosave = true
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "yamldoc"
|
@@ -0,0 +1,219 @@
|
|
1
|
+
# puts config.methods.inspect
|
2
|
+
# puts config.properties.inspect
|
3
|
+
# puts config.key_type
|
4
|
+
|
5
|
+
# puts config.String[0]
|
6
|
+
# config.defaults.sendary = "overwritten"
|
7
|
+
# config.defaults["sendary"] = "overwritten"
|
8
|
+
# config.defaults[:sendary] = "overwritten2"
|
9
|
+
# config.ymldoc_pfx = "yml_"
|
10
|
+
# config.reload_hooks
|
11
|
+
# puts config.methods.inspect
|
12
|
+
# puts config.properties.inspect
|
13
|
+
# puts config.yml_methods.inspect
|
14
|
+
# puts config.yml_properties.inspect
|
15
|
+
# puts config.properties.each {|p| puts "#{p} => " + eval("config.#{p}").inspect }
|
16
|
+
# puts config.properties.pretty_print
|
17
|
+
# puts config.filename
|
18
|
+
|
19
|
+
|
20
|
+
# config.load("new.yml")
|
21
|
+
# config.save
|
22
|
+
# puts ""
|
23
|
+
# config.save() do |c|
|
24
|
+
# c.leftjustify = true
|
25
|
+
# end
|
26
|
+
# config.save
|
27
|
+
# puts config.yml_service_hooks.inspect
|
28
|
+
#
|
29
|
+
# puts config.hooks.inspect
|
30
|
+
# config.hook_pfx=("_")
|
31
|
+
# puts config.hook_pfx.inspect
|
32
|
+
# config.reload_hooks
|
33
|
+
# puts config._hooks.inspect
|
34
|
+
# puts config.hooks.inspect
|
35
|
+
# config.save
|
36
|
+
|
37
|
+
# require 'matrix'
|
38
|
+
# config.matrix = Matrix[ [25, 93], [-1, 66] ]
|
39
|
+
|
40
|
+
# class Car
|
41
|
+
# # attr_accessor :wheels, :engine, :doors, :trunk
|
42
|
+
# @wheels = 4
|
43
|
+
# @engine = "Big V-6"
|
44
|
+
# @doors = 5
|
45
|
+
# # def initialize(*args, &block)
|
46
|
+
# # case args.first
|
47
|
+
# # when Hash
|
48
|
+
# # args.first.each do |k,v|
|
49
|
+
# # s = k.to_s
|
50
|
+
# # eval "self.#{s} = v"
|
51
|
+
# # end
|
52
|
+
# # end
|
53
|
+
# # end
|
54
|
+
# end
|
55
|
+
|
56
|
+
# car = Car.new :wheels => 4, :engine => "2.4 Litre Diesel", :doors => 5
|
57
|
+
# car = Car.new
|
58
|
+
# puts car.inspect
|
59
|
+
|
60
|
+
# config.car = car
|
61
|
+
# config.car.trunk = "hatchback"
|
62
|
+
# car.engine = "2.4 Litre Diesel"
|
63
|
+
# config.car = Car.new :wheels => 4, :engine => "2.4 Litre Diesel", :doors => 5
|
64
|
+
|
65
|
+
# config.car.engine = "No engine"
|
66
|
+
# car.engine = "EasyJet"
|
67
|
+
|
68
|
+
# puts ""
|
69
|
+
# puts car.class.to_s.match("Array|String|Hash")
|
70
|
+
# puts car.class.to_s.match("Array|String|Hash|Car")
|
71
|
+
# puts config.yml_filename
|
72
|
+
|
73
|
+
# puts "car=#{car.inspect}"
|
74
|
+
# puts ""
|
75
|
+
# puts "config.car=#{config.car.inspect}"
|
76
|
+
# puts "------------------------------------------------------"
|
77
|
+
# puts ""
|
78
|
+
|
79
|
+
# config._foo = "bartender"
|
80
|
+
# config._foo = String.new "bartender"
|
81
|
+
# config._root = "somestring"
|
82
|
+
|
83
|
+
# # service hook
|
84
|
+
# config._filename = "filename"
|
85
|
+
# config._.filename = "filename"
|
86
|
+
# config._.merge! { filename => "filename" }
|
87
|
+
|
88
|
+
# config.defaults.insert "x-plane"
|
89
|
+
# config.defaults.delete "a"
|
90
|
+
# config.defaults.update({})
|
91
|
+
# config.defaults.replace "one"=> 1, :two => 2
|
92
|
+
#
|
93
|
+
#
|
94
|
+
# config.tee = "chocolate"
|
95
|
+
# puts "config[\"tee\"]=#{config["tee"]}"
|
96
|
+
# config.tee.upcase!
|
97
|
+
#
|
98
|
+
# config.moon = "the lazy cat"
|
99
|
+
# config.moon.upcase!
|
100
|
+
#
|
101
|
+
# puts config.inspect
|
102
|
+
# config.__write_file
|
103
|
+
|
104
|
+
# puts config.sub1
|
105
|
+
# config.sub1.a1 = [1]
|
106
|
+
# # puts config.sub1.a1.inspect
|
107
|
+
# config.sub1.a1[1] = 2
|
108
|
+
# # config.sub1.a1 << 2
|
109
|
+
# # puts config.sub1.a1.inspect
|
110
|
+
# config.sub1.a1 = [1,2,3]
|
111
|
+
# # config.sub1.a1.insert (0,3)
|
112
|
+
# config.sub1.a1.compact!
|
113
|
+
# # puts config.sub1.a1.inspect
|
114
|
+
|
115
|
+
# config[1] = "foo"
|
116
|
+
# config[2] = "bar"
|
117
|
+
# puts config.inspect
|
118
|
+
# config._save
|
119
|
+
|
120
|
+
# require 'yamldoc'
|
121
|
+
# class Settings < AutoYamlDoc
|
122
|
+
# self.filename = File.expand_path("~/.moonshadow")
|
123
|
+
# self.key_type = Symbol
|
124
|
+
# self.deep_clone = true
|
125
|
+
# # self.service_hook = "yml_"
|
126
|
+
# end
|
127
|
+
|
128
|
+
# config = Settings.new() do |c|
|
129
|
+
# # c.defaults = {"one"=> 1, :two => 2}
|
130
|
+
# c.defaults = {"a"=> 1, :sendary => 3}
|
131
|
+
# c.defaults.array = [1,2,3,4]
|
132
|
+
# # config = [1,2,3,4]
|
133
|
+
# end
|
134
|
+
|
135
|
+
# puts "YamlDoc "+YamlDoc.properties.inspect
|
136
|
+
# puts "AutoYaml "+AutoYamlDoc.properties.inspect
|
137
|
+
# puts "Settings "+Settings.properties.inspect
|
138
|
+
# config = Settings.new
|
139
|
+
# config.key_type = String
|
140
|
+
# puts "object "+config.properties.inspect
|
141
|
+
# puts "object "+config.instance_eval("@_").inspect
|
142
|
+
#
|
143
|
+
# puts "YamlDoc "+YamlDoc.properties.inspect
|
144
|
+
# puts "AutoYaml "+AutoYamlDoc.properties.inspect
|
145
|
+
# puts "Settings "+Settings.properties.inspect
|
146
|
+
#
|
147
|
+
# puts "AutoYaml autosave = "+AutoYamlDoc.autosave.inspect
|
148
|
+
# puts "YamlDoc autosave = "+YamlDoc.autosave.inspect
|
149
|
+
# puts "YamlDoc key_type = "+YamlDoc.key_type.inspect
|
150
|
+
|
151
|
+
|
152
|
+
# puts "AutoYamlDoc.object_detection=#{AutoYamlDoc.object_detection}"
|
153
|
+
|
154
|
+
# config = Settings.new("filename")
|
155
|
+
# config = Settings.new("file.yml"){}
|
156
|
+
# config = Settings.new :filename => "file.yml", :autosave => true
|
157
|
+
# config = Settings.new(:filename => "file.yml", :autosave => true){}
|
158
|
+
# config = Settings.new
|
159
|
+
|
160
|
+
# config.sub2.hash1.two = 2
|
161
|
+
# config.sub2.hash1.three = 3
|
162
|
+
# config.sub1.a1 = [1,2,3]
|
163
|
+
# config.strings.about = "About string for this ruby application"
|
164
|
+
#
|
165
|
+
# require 'matrix'
|
166
|
+
# config.matrix = Matrix[ [25, 93], [-1, 66] ]
|
167
|
+
# config.strings.about.reverse!
|
168
|
+
# puts config.strings.about
|
169
|
+
|
170
|
+
# puts config.sub1
|
171
|
+
# config.sub1.a1 = [1]
|
172
|
+
# puts config.sub1.a1.inspect
|
173
|
+
# # config.sub1.a1 = [2]
|
174
|
+
# config.sub1.a1 << 2
|
175
|
+
# puts config.sub1.a1.inspect
|
176
|
+
# config.sub1.a1 = [1,2,3]
|
177
|
+
# config.sub1.a1.insert (0,3)
|
178
|
+
# puts config.sub1.a1.inspect
|
179
|
+
#
|
180
|
+
# # puts config.sub1.hash1.inspect
|
181
|
+
# config.sub1.sub2.hash1 = {"2" => 2, "three" => 3, :three => "three"}
|
182
|
+
# puts config.sub1.sub2.hash1.inspect
|
183
|
+
|
184
|
+
# config = Settings.new "filename"
|
185
|
+
# config = Settings.new "filename2"
|
186
|
+
# config = Settingslogic.new "filename2"
|
187
|
+
# puts config.ancestors
|
188
|
+
# config = Settings.new(:config1 => 1, :config2 => 2)
|
189
|
+
# config[:config1] = 1
|
190
|
+
# config[:config2] = 2
|
191
|
+
# config[:blue] = "Nixon"
|
192
|
+
# puts config.blue
|
193
|
+
# # config["blue"] = 3
|
194
|
+
# config["blue"] = "four"
|
195
|
+
# puts config.blue
|
196
|
+
|
197
|
+
# puts ""
|
198
|
+
# # puts config[:config2]
|
199
|
+
# # puts config.settings
|
200
|
+
# puts config.blue
|
201
|
+
# # puts config.config2
|
202
|
+
#
|
203
|
+
# config.blue = "canary"
|
204
|
+
# puts config.blue
|
205
|
+
|
206
|
+
# config.sub1.hash1 = {"2" => 2, "three" => 3, :three => "three"}
|
207
|
+
# config.sub1 = {}
|
208
|
+
|
209
|
+
# config.foo = {"hash1"=>"one"}
|
210
|
+
# config.yellow = true
|
211
|
+
|
212
|
+
# config = Settings.new
|
213
|
+
# config.transaction("file.yml", hash){ |config|
|
214
|
+
# # config.defaults = {"one"=> 1, :two => 2}
|
215
|
+
# # config.defaults.array = [1,2,3,4]
|
216
|
+
# config.defaults = {"one"=> 1, :two => 2}
|
217
|
+
# # config = [1,2,3,4]
|
218
|
+
# }
|
219
|
+
|
data/spec/settings.rb
ADDED
data/spec/settings.yml
ADDED
data/spec/settings2.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ruby-debug'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
+
require 'yamldoc'
|
8
|
+
require 'settings'
|
9
|
+
require 'settings2'
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
|
3
|
+
describe "YamlDoc" do
|
4
|
+
it "should be a hash" do
|
5
|
+
Settings.send(:instance).should be_is_a(Hash)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should access settings" do
|
9
|
+
Settings.setting2.should == 5
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should access nested settings" do
|
13
|
+
Settings.setting1.setting1_child.should == "saweet"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should access deep nested settings" do
|
17
|
+
Settings.setting1.deep.another.should == "my value"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should access extra deep nested settings" do
|
21
|
+
Settings.setting1.deep.child.value.should == 2
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should enable erb" do
|
25
|
+
Settings.setting3.should == 25
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should namespace settings" do
|
29
|
+
Settings2.setting1_child.should == "saweet"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should distinguish nested keys" do
|
33
|
+
Settings.language.haskell.paradigm.should == 'functional'
|
34
|
+
Settings.language.smalltalk.paradigm.should == 'object oriented'
|
35
|
+
end
|
36
|
+
end
|
data/yamldoc.gemspec
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{yamldoc}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["dreamcat4, Ben Johnson"]
|
12
|
+
s.date = %q{2009-10-15}
|
13
|
+
s.email = %q{dreamcat4@gmail.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"CHANGELOG.rdoc",
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION.yml",
|
25
|
+
"init.rb",
|
26
|
+
"lib/class_attributes.rb",
|
27
|
+
"lib/yamldoc.rb",
|
28
|
+
"rails/init.rb",
|
29
|
+
"spec/examples_unsorted.rb",
|
30
|
+
"spec/settings.rb",
|
31
|
+
"spec/settings.yml",
|
32
|
+
"spec/settings2.rb",
|
33
|
+
"spec/spec_helper.rb",
|
34
|
+
"spec/yamldoc_spec.rb",
|
35
|
+
"yamldoc.gemspec"
|
36
|
+
]
|
37
|
+
s.homepage = %q{http://github.com/dreamcat4/yamldoc}
|
38
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubyforge_project = %q{}
|
41
|
+
s.rubygems_version = %q{1.3.4}
|
42
|
+
s.summary = %q{A simple solution for ERB enabled YAML file.}
|
43
|
+
s.test_files = [
|
44
|
+
"spec/examples_unsorted.rb",
|
45
|
+
"spec/settings.rb",
|
46
|
+
"spec/settings2.rb",
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
"spec/yamldoc_spec.rb"
|
49
|
+
]
|
50
|
+
|
51
|
+
if s.respond_to? :specification_version then
|
52
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
53
|
+
s.specification_version = 3
|
54
|
+
|
55
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
56
|
+
else
|
57
|
+
end
|
58
|
+
else
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yamldoc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- dreamcat4, Ben Johnson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-15 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: dreamcat4@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- .gitignore
|
27
|
+
- CHANGELOG.rdoc
|
28
|
+
- LICENSE
|
29
|
+
- README.rdoc
|
30
|
+
- Rakefile
|
31
|
+
- VERSION.yml
|
32
|
+
- init.rb
|
33
|
+
- lib/class_attributes.rb
|
34
|
+
- lib/yamldoc.rb
|
35
|
+
- rails/init.rb
|
36
|
+
- spec/examples_unsorted.rb
|
37
|
+
- spec/settings.rb
|
38
|
+
- spec/settings.yml
|
39
|
+
- spec/settings2.rb
|
40
|
+
- spec/spec_helper.rb
|
41
|
+
- spec/yamldoc_spec.rb
|
42
|
+
- yamldoc.gemspec
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/dreamcat4/yamldoc
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --charset=UTF-8
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: ""
|
67
|
+
rubygems_version: 1.3.4
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: A simple solution for ERB enabled YAML file.
|
71
|
+
test_files:
|
72
|
+
- spec/examples_unsorted.rb
|
73
|
+
- spec/settings.rb
|
74
|
+
- spec/settings2.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
- spec/yamldoc_spec.rb
|