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).



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/using_yaml.rb', line 88

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


121
122
123
124
125
126
127
128
129
130
131
132
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
# File 'lib/using_yaml.rb', line 121

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 yaml

    # 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?
      UsingYAML.add_extensions(nil)
    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