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