Class: Moneta::Transformer

Inherits:
Proxy
  • Object
show all
Defined in:
lib/moneta/transformer.rb

Overview

Transforms keys and values (Marshal, YAML, JSON, Base64, MD5, …). You can bypass the transformer (e.g. serialization) by using the ‘:raw` option.

Examples:

Add ‘Moneta::Transformer` to proxy stack

Moneta.build do
  use :Transformer key: [:marshal, :escape], value: [:marshal]
  adapter :File, dir: 'data'
end

Bypass serialization

store.store('key', 'value', raw: true)
store['key'] # raises an Exception
store.load('key', raw: true) # returns 'value'

store['key'] = 'value'
store.load('key', raw: true) # returns "\x04\bI\"\nvalue\x06:\x06ET"

Instance Attribute Summary

Attributes inherited from Proxy

#adapter

Instance Method Summary collapse

Methods inherited from Proxy

#clear, #close, #config, features_mask, not_supports

Methods included from Config

#config, included

Methods included from Defaults

#[], #[]=, #close, #decrement, #fetch, included, #update

Methods included from OptionSupport

#expires, #prefix, #raw, #with

Constructor Details

#initialize(adapter, options = {}) ⇒ Transformer

Returns a new instance of Transformer.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/moneta/transformer.rb', line 31

def initialize(adapter, options = {})
  super

  if config.key.empty?
    @key_decodable = true
  else
    @key_transforms = load_transforms(
      config.key,
      options.merge(serialize_unless_string: config.serialize_keys_unless_string)
    )
    @key_decodable = @key_transforms.all?(&:decodable?)
    @key_encoder = make_encoder(@key_transforms)
    if @key_decodable
      @key_decoder = make_decoder(@key_transforms)
    end
  end

  unless config.value.empty?
    @value_transforms = load_transforms(config.value, options)
    raise "Not all value transforms are decodable (#{@value_transforms.reject(&:decodable?)})" \
      unless @value_transforms.all?(&:decodable?)
    @value_encoder = make_encoder(@value_transforms)
    @value_decoder = make_decoder(@value_transforms)
  end
end

Instance Method Details

#create(key, value, options = {}) ⇒ Object



102
103
104
# File 'lib/moneta/transformer.rb', line 102

def create(key, value, options = {})
  super(encode_key(key), encode_value(value, options[:raw]), options)
end

#delete(key, options = {}) ⇒ Object



115
116
117
# File 'lib/moneta/transformer.rb', line 115

def delete(key, options = {})
  decode_value(super(encode_key(key), options), options[:raw])
end

#each_keyObject

Yields keys from the underlying store that it is possible to decode. The method tries to avoid decoding any keys that are definitely invalid by checking the ‘decodable?` method, but also ignores any keys that throw errors while decoding.

Raises:

  • (NotImplementedError)


83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/moneta/transformer.rb', line 83

def each_key
  raise NotImplementedError, "each_key is not supported on this transformer" \
    unless supports? :each_key

  return super unless block_given?

  super do |key|
    next unless encoded_key?(key)
    yield decode_key(key)
  rescue
    # Silently ignore any error raised trying to decode the key.
    next
  end
end

#featuresObject



66
67
68
69
70
71
72
73
# File 'lib/moneta/transformer.rb', line 66

def features
  @features ||=
    begin
      features = super
      features -= [:each_key] unless supports?(:each_key)
      features.freeze
    end
end

#fetch_values(*keys, raw: false, **options) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/moneta/transformer.rb', line 123

def fetch_values(*keys, raw: false, **options)
  if block_given?
    encoded_keys = keys.map { |key| encode_key(key) }
    dictionary = encoded_keys.zip(keys).to_h

    encoded_values =
      super(*encoded_keys, **options) do |encoded_key|
        decoded_value = yield dictionary[encoded_key]
        encode_value(decoded_value, raw) if decoded_value != nil
      end

    encoded_values.map { |value| decode_value(value, raw) }
  else
    values_at(*keys, **options)
  end
end

#increment(key, amount = 1, options = {}) ⇒ Object



98
99
100
# File 'lib/moneta/transformer.rb', line 98

def increment(key, amount = 1, options = {})
  super(encode_key(key), amount, options)
end

#key?(key, options = {}) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/moneta/transformer.rb', line 75

def key?(key, options = {})
  super(encode_key(key), options)
end

#load(key, options = {}) ⇒ Object



106
107
108
# File 'lib/moneta/transformer.rb', line 106

def load(key, options = {})
  decode_value(super(encode_key(key), options), options[:raw])
end

#merge!(pairs, options = {}) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/moneta/transformer.rb', line 150

def merge!(pairs, options = {})
  encoded_pairs = pairs.map { |key, value| [encode_key(key), encode_value(value, options[:raw])] }
  if block_given?
    key_dictionary = encoded_pairs.map(&:first).zip(pairs.map(&:first)).to_h
    value_dictionary = encoded_pairs.map(&:last).zip(pairs.map(&:last)).to_h

    super(encoded_pairs, options) do |encoded_key, existing_encoded_value, new_encoded_value|
      key = key_dictionary[encoded_key]
      existing_value = decode_value(existing_encoded_value, options[:raw])
      new_value = value_dictionary[new_encoded_value]
      value = yield(key, existing_value, new_value)
      encode_value(value, options[:raw])
    end
  else
    super(encoded_pairs, options)
  end
end

#slice(*keys, raw: false, **options) ⇒ Object



140
141
142
143
144
145
146
147
148
# File 'lib/moneta/transformer.rb', line 140

def slice(*keys, raw: false, **options)
  encoded_keys = keys.map { |key| encode_key(key) }
  dictionary = encoded_keys.zip(keys).to_h

  encoded_pairs = super(*encoded_keys, **options)
  encoded_pairs.map do |encoded_key, encoded_value|
    [dictionary[encoded_key], decode_value(encoded_value, raw)]
  end
end

#store(key, value, options = {}) ⇒ Object



110
111
112
113
# File 'lib/moneta/transformer.rb', line 110

def store(key, value, options = {})
  super(encode_key(key), encode_value(value, options[:raw]), options)
  value
end

#supports?(feature) ⇒ Boolean

Returns:

  • (Boolean)


57
58
59
60
61
62
63
64
# File 'lib/moneta/transformer.rb', line 57

def supports?(feature)
  supported = super
  if supported && feature == :each_key && !@key_decodable
    false
  else
    supported
  end
end

#values_at(*keys, raw: false, **options) ⇒ Object



119
120
121
# File 'lib/moneta/transformer.rb', line 119

def values_at(*keys, raw: false, **options)
  super(*keys.map { |key| encode_key(key) }, **options).map { |value| decode_value(value, raw) }
end