Class: Representable::Binding

Inherits:
Object
  • Object
show all
Includes:
Factories
Defined in:
lib/representable/binding.rb

Overview

The flow when parsing is Binding#read_fragment -> Populator -> Deserializer. Actual parsing the fragment from the document happens in Binding#read, everything after that is generic.

Serialization: Serializer -> frag/[frag]/frag -> Binding#write

Direct Known Subclasses

Hash::Binding, Object::Binding, XML::Binding

Defined Under Namespace

Modules: Collection, Factories, Hash Classes: FragmentNotFound, Options

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Factories

#deserializer, #deserializer_class, #populator, #populator_class, #serializer, #serializer_class

Constructor Details

#initialize(definition, parent_decorator) ⇒ Binding

Returns a new instance of Binding.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/representable/binding.rb', line 18

def initialize(definition, parent_decorator)
  @definition       = definition
  @parent_decorator = parent_decorator # DISCUSS: where's this needed?

  # static options. do this once.
  @representable    = @definition.representable?
  @name             = @definition.name
  @skip_filters     = self[:readable]==false || self[:writeable]==false || self[:if] # Does this binding contain :if, :readable or :writeable settings?
  @getter           = @definition.getter
  @setter           = @definition.setter
  @array            = @definition.array?
  @typed            = @definition.typed?
  @has_default      = @definition.has_default?
end

Instance Attribute Details

#arrayObject (readonly) Also known as: array?

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def array
  @array
end

#cached_representerObject

Returns the value of attribute cached_representer.



155
156
157
# File 'lib/representable/binding.rb', line 155

def cached_representer
  @cached_representer
end

#getterObject (readonly)

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def getter
  @getter
end

#has_defaultObject (readonly) Also known as: has_default?

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def has_default
  @has_default
end

#nameObject (readonly)

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def name
  @name
end

#representableObject (readonly) Also known as: representable?

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def representable
  @representable
end

#representedObject (readonly)

TODO: make private/remove.



33
34
35
# File 'lib/representable/binding.rb', line 33

def represented
  @represented
end

#setterObject (readonly)

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def setter
  @setter
end

#skip_filtersObject (readonly) Also known as: skip_filters?

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def skip_filters
  @skip_filters
end

#typedObject (readonly) Also known as: typed?

DISCUSS: an overall strategy to speed up option reads will come around 3.0.



36
37
38
# File 'lib/representable/binding.rb', line 36

def typed
  @typed
end

#user_optionsObject (readonly)

TODO: make private/remove.



33
34
35
# File 'lib/representable/binding.rb', line 33

def user_options
  @user_options
end

Class Method Details

.build(definition, *args) ⇒ Object



12
13
14
15
16
# File 'lib/representable/binding.rb', line 12

def self.build(definition, *args)
  # DISCUSS: move #create_binding to this class?
  return definition.create_binding(*args) if definition[:binding]
  build_for(definition, *args)
end

Instance Method Details

#[](name) ⇒ Object



130
131
132
# File 'lib/representable/binding.rb', line 130

def [](name)
  @definition[name]
end

#asObject

DISCUSS: private?



43
44
45
# File 'lib/representable/binding.rb', line 43

def as # DISCUSS: private?
  @as ||= evaluate_option(:as)
end

#compile_fragment(doc) ⇒ Object

Retrieve value and write fragment to the doc.



54
55
56
57
58
59
# File 'lib/representable/binding.rb', line 54

def compile_fragment(doc)
  evaluate_option(:writer, doc) do
    value = render_filter(get, doc)
    write_fragment(doc, value)
  end
end

#default_for(value) ⇒ Object



142
143
144
145
# File 'lib/representable/binding.rb', line 142

def default_for(value)
  return self[:default] if skipable_empty_value?(value)
  value
end

#evaluate_option(name, *args) ⇒ Object

Evaluate the option (either nil, static, a block or an instance method call) or executes passed block when option not defined.



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/representable/binding.rb', line 118

def evaluate_option(name, *args)
  unless proc = @definition[name] # TODO: this could dispatch directly to the @definition using #send?
    return yield if block_given?
    return
  end

  # TODO: it would be better if user_options was nil per default and then we just don't pass it into lambdas.
  options = self[:pass_options] ? Options.new(self, user_options, represented, parent_decorator) : user_options

  proc.evaluate(exec_context, *(args<<options)) # from Uber::Options::Value.
end

#getObject



96
97
98
99
100
# File 'lib/representable/binding.rb', line 96

def get
  evaluate_option(:getter) do
    exec_context.send(getter)
  end
end

#parse_filter(value, doc) ⇒ Object



92
93
94
# File 'lib/representable/binding.rb', line 92

def parse_filter(value, doc)
  evaluate_option(:parse_filter, value, doc) { value }
end

#read_fragment(doc) ⇒ Object



82
83
84
85
86
# File 'lib/representable/binding.rb', line 82

def read_fragment(doc)
  fragment = read(doc) # scalar, Array, or Hash (abstract format) or un-deserialised fragment(s).

  populator.call(fragment, doc)
end

#render_filter(value, doc) ⇒ Object



88
89
90
# File 'lib/representable/binding.rb', line 88

def render_filter(value, doc)
  evaluate_option(:render_filter, value, doc) { value }
end

#render_fragment(value, doc) ⇒ Object



76
77
78
79
80
# File 'lib/representable/binding.rb', line 76

def render_fragment(value, doc)
  fragment = serialize(value) { return } # render fragments of hash, xml, yaml.

  write(doc, fragment)
end

#representer_module_for(object, *args) ⇒ Object

DISCUSS: do we really need that?

1.38      0.104     0.021     0.000     0.083    40001   Representable::Binding#representer_module_for
1.13      0.044     0.017     0.000     0.027    40001   Representable::Binding#representer_module_for (with memoize).


111
112
113
114
# File 'lib/representable/binding.rb', line 111

def representer_module_for(object, *args)
  # TODO: cache this!
  evaluate_option(:extend, object) # TODO: pass args? do we actually have args at the time this is called (compile-time)?
end

#set(value) ⇒ Object



102
103
104
105
106
# File 'lib/representable/binding.rb', line 102

def set(value)
  evaluate_option(:setter, value) do
    exec_context.send(setter, value)
  end
end

#skipable_empty_value?(value) ⇒ Boolean

1.55 0.031 0.022 0.000 0.009 60004 Representable::Binding#skipable_empty_value?

1.51      0.030     0.022     0.000     0.008    60004   Representable::Binding#skipable_empty_value?

after polymorphism: 1.44 0.031 0.022 0.000 0.009 60002 Representable::Binding#skipable_empty_value?

Returns:

  • (Boolean)


138
139
140
# File 'lib/representable/binding.rb', line 138

def skipable_empty_value?(value)
  value.nil? and not self[:render_nil]
end

#uncompile_fragment(doc) ⇒ Object

Parse value from doc and update the model property.



62
63
64
65
66
# File 'lib/representable/binding.rb', line 62

def uncompile_fragment(doc)
  evaluate_option(:reader, doc) do
    read_fragment(doc)
  end
end

#update!(represented, user_options) ⇒ Object

Note: this method is experimental.



148
149
150
151
152
153
# File 'lib/representable/binding.rb', line 148

def update!(represented, user_options)
  @represented      = represented
  @user_options     = user_options

  setup_exec_context!
end

#write_fragment(doc, value) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/representable/binding.rb', line 68

def write_fragment(doc, value)
  value = default_for(value)

  return if skipable_empty_value?(value)

  render_fragment(value, doc)
end