lib/moneta/transformer.rb in moneta-0.7.1 vs lib/moneta/transformer.rb in moneta-0.7.2

- old
+ new

@@ -8,116 +8,139 @@ # adapter :File, :dir => 'data' # end # # @example Bypass serialization # store.store('key', 'value', :raw => true) - # store['key'] => Error - # store.load('key', :raw => true) => 'value' + # store['key'] # raises an Exception + # store.load('key', :raw => true) # returns 'value' # # store['key'] = 'value' - # store.load('key', :raw => true) => "\x04\bI\"\nvalue\x06:\x06ET" + # store.load('key', :raw => true) # returns "\x04\bI\"\nvalue\x06:\x06ET" # # @api public class Transformer < Proxy class << self alias_method :original_new, :new - # Constructor - # # @param [Moneta store] adapter The underlying store # @param [Hash] options # @return [Transformer] new Moneta transformer # @option options [Array] :key List of key transformers in the order in which they should be applied # @option options [Array] :value List of value transformers in the order in which they should be applied # @option options [String] :prefix Prefix string for key namespacing (Used by the :prefix key transformer) # @option options [String] :secret HMAC secret to verify values (Used by the :hmac value transformer) # @option options [Integer] :maxlen Maximum key length (Used by the :truncate key transformer) - # @option options [Boolean] :quiet Disable error message def new(adapter, options = {}) keys = [options[:key]].flatten.compact values = [options[:value]].flatten.compact raise ArgumentError, 'Option :key or :value is required' if keys.empty? && values.empty? options[:prefix] ||= '' if keys.include?(:prefix) - name = class_name(options[:quiet] ? 'Quiet' : '', keys, values) - const_set(name, compile(options, keys, values)) unless const_defined?(name) + name = class_name(keys, values) + const_set(name, compile(keys, values)) unless const_defined?(name) const_get(name).original_new(adapter, options) end private - def compile(options, keys, values) + def compile(keys, values) @key_validator ||= compile_validator(KEY_TRANSFORMER) @value_validator ||= compile_validator(VALUE_TRANSFORMER) raise ArgumentError, 'Invalid key transformer chain' if @key_validator !~ keys.map(&:inspect).join raise ArgumentError, 'Invalid value transformer chain' if @value_validator !~ values.map(&:inspect).join - key = compile_transformer(keys, 'key') - klass = Class.new(self) klass.class_eval <<-end_eval, __FILE__, __LINE__ def initialize(adapter, options = {}) super #{compile_initializer('key', keys)} #{compile_initializer('value', values)} end + end_eval + + key = compile_transformer(keys, 'key') + dump = compile_transformer(values, 'value') + load = compile_transformer(values.reverse, 'value', 1) + + if values.empty? + compile_key_transformer(klass, key) + elsif keys.empty? + compile_value_transformer(klass, load, dump) + else + compile_key_value_transformer(klass, key, load, dump) + end + + klass + end + + def compile_key_transformer(klass, key) + klass.class_eval <<-end_eval, __FILE__, __LINE__ def key?(key, options = {}) @adapter.key?(#{key}, options) end def increment(key, amount = 1, options = {}) @adapter.increment(#{key}, amount, options) end + def load(key, options = {}) + options.include?(:raw) && (options = options.dup; options.delete(:raw)) + @adapter.load(#{key}, options) + end + def store(key, value, options = {}) + options.include?(:raw) && (options = options.dup; options.delete(:raw)) + @adapter.store(#{key}, value, options) + end + def delete(key, options = {}) + options.include?(:raw) && (options = options.dup; options.delete(:raw)) + @adapter.delete(#{key}, options) + end end_eval + end - if values.empty? - klass.class_eval <<-end_eval, __FILE__, __LINE__ - def load(key, options = {}) - options.delete(:raw) - @adapter.load(#{key}, options) - end - def store(key, value, options = {}) - options.delete(:raw) - @adapter.store(#{key}, value, options) - end - def delete(key, options = {}) - options.delete(:raw) - @adapter.delete(#{key}, options) - end - end_eval - else - dump = compile_transformer(values, 'value') - load = compile_transformer(values.reverse, 'value', 1) + def compile_value_transformer(klass, load, dump) + klass.class_eval <<-end_eval, __FILE__, __LINE__ + def load(key, options = {}) + raw = options.include?(:raw) && (options = options.dup; options.delete(:raw)) + value = @adapter.load(key, options) + value && !raw ? #{load} : value + end + def store(key, value, options = {}) + raw = options.include?(:raw) && (options = options.dup; options.delete(:raw)) + @adapter.store(key, raw ? value : #{dump}, options) + value + end + def delete(key, options = {}) + raw = options.include?(:raw) && (options = options.dup; options.delete(:raw)) + value = @adapter.delete(key, options) + value && !raw ? #{load} : value + end + end_eval + end - klass.class_eval <<-end_eval, __FILE__, __LINE__ - def load(key, options = {}) - raw = options.delete(:raw) - value = @adapter.load(#{key}, options) - begin - return #{load} if value && !raw - rescue Exception => ex - #{options[:quiet] ? '' : 'puts "Tried to load invalid value: #{ex.message}"'} - end - value - end - def store(key, value, options = {}) - raw = options.delete(:raw) - @adapter.store(#{key}, raw ? value : #{dump}, options) - value - end - def delete(key, options = {}) - raw = options.delete(:raw) - value = @adapter.delete(#{key}, options) - begin - return #{load} if value && !raw - rescue Exception => ex - #{options[:quiet] ? '' : 'puts "Tried to delete invalid value: #{ex.message}"'} - end - value - end - end_eval - end - klass + def compile_key_value_transformer(klass, key, load, dump) + klass.class_eval <<-end_eval, __FILE__, __LINE__ + def key?(key, options = {}) + @adapter.key?(#{key}, options) + end + def increment(key, amount = 1, options = {}) + @adapter.increment(#{key}, amount, options) + end + def load(key, options = {}) + raw = options.include?(:raw) && (options = options.dup; options.delete(:raw)) + value = @adapter.load(#{key}, options) + value && !raw ? #{load} : value + end + def store(key, value, options = {}) + raw = options.include?(:raw) && (options = options.dup; options.delete(:raw)) + @adapter.store(#{key}, raw ? value : #{dump}, options) + value + end + def delete(key, options = {}) + raw = options.include?(:raw) && (options = options.dup; options.delete(:raw)) + value = @adapter.delete(#{key}, options) + value && !raw ? #{load} : value + end + end_eval end # Compile option initializer def compile_initializer(type, transformers) transformers.map do |name| @@ -147,11 +170,11 @@ code % value end end end - def class_name(prefix, keys, values) - prefix << (keys.empty? ? '' : keys.map(&:to_s).map(&:capitalize).join << 'Key') << + def class_name(keys, values) + (keys.empty? ? '' : keys.map(&:to_s).map(&:capitalize).join << 'Key') << (values.empty? ? '' : values.map(&:to_s).map(&:capitalize).join << 'Value') end end end end