Module: UsingYAML::ClassMethods

Defined in:
lib/using_yaml.rb

Instance Method Summary collapse

Instance Method Details

#using_yaml(*args) ⇒ Object

Used to configure UsingYAML for a class by defining what files should be loaded and from where.

include UsingYAML
using_yaml :foo, :bar, :path => "/some/where"

args can contain either filenames or a hash which specifices a path which contains the corresponding files.

The value of :path must either be a string or Proc (see using_yaml_path for more information on overriding paths).



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/using_yaml.rb', line 100

def using_yaml(*args)
  # Include the instance methods which provide accessors and
  # mutators for reading/writing from/to the YAML objects.
  include InstanceMethods

  # Each argument is either a filename or a :path option
  args.each do |arg|
    case arg
    when Symbol, String
      # Define accessors for this file
      using_yaml_file(arg.to_s)
    when Hash
      # Currently only accepts { :path => ... }
      next unless arg.size == 1 && arg.keys.first == :path
      
      # Take note of the path
      UsingYAML.path = [self.inspect, arg.values.first]
    end
  end
end

#using_yaml_file(filename) ⇒ Object

Special attr_accessor for the suppiled filename such that files are intelligently loaded/written to disk.

using_yaml_file(:foo) # => attr_accessor(:foo) + some magic

If class Example is setup with the above, then:

example = Example.new
example.foo      # => loads from foo.yml
example.foo.bar  # => equivalent to example.foo['bar']
example.foo.save # => serialises to foo.yml


133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/using_yaml.rb', line 133

def using_yaml_file(filename)
  # Define an reader for filename such that the corresponding
  # YAML file is loaded. Example: using_yaml_file(:foo) will look
  # for foo.yml in the specified path.
  define_method(filename) do
    # Work out the absolute path for the filename and get a handle
    # on the cachestore for that file.
    pathname = using_yaml_path.join("#{filename}.yml").expand_path
    yaml     = (@using_yaml_cache ||= {})[pathname]

    # If the yaml exists in our cache, then we don't need to hit
    # the disk.
    return yaml if @using_yaml_cache.has_key? pathname

    # Safe disk read which either reads and parses a YAML object
    # (and caches it against future reads) or graciously ignores
    # the file's existence. Note that an error will appear on
    # stderr to avoid typos (or similar) from causing unexpected
    # behavior. See +UsingYAML.squelch!+ if you wish to hide the
    # error.
    begin
      @using_yaml_cache[pathname] = UsingYAML.add_extensions(YAML.load_file(pathname), pathname)
    rescue Exception => e
      $stderr.puts "(UsingYAML) Could not load #{filename}: #{e.message}" unless UsingYAML.squelched?
      @using_yaml_cache[pathname] = UsingYAML.add_extensions(nil, pathname)
    end
  end

  # Define a writer for filename such that the incoming object is
  # treated as a UsingYAML-ized Hash (magical properties). Be
  # aware that the incoming object will not be saved to disk
  # unless you explicitly do so.
  define_method("#{filename}=".to_sym) do |object|
    # Work out the absolute path for the filename and get a handle
    # on the cachestore for that file.
    pathname = using_yaml_path.join("#{filename}.yml").expand_path
    (@using_yaml_cache ||= {})[pathname] = UsingYAML.add_extensions(object, pathname)
  end
end