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.



158
159
160
# File 'lib/representable/binding.rb', line 158

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



133
134
135
# File 'lib/representable/binding.rb', line 133

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.



57
58
59
60
61
62
# File 'lib/representable/binding.rb', line 57

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

#default_for(value) ⇒ Object



145
146
147
148
# File 'lib/representable/binding.rb', line 145

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.



121
122
123
124
125
126
127
128
129
130
131
# File 'lib/representable/binding.rb', line 121

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



99
100
101
102
103
# File 'lib/representable/binding.rb', line 99

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

#parse_filter(value, doc) ⇒ Object



95
96
97
# File 'lib/representable/binding.rb', line 95

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

#read_fragment(doc) ⇒ Object



85
86
87
88
89
# File 'lib/representable/binding.rb', line 85

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



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

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

#render_fragment(value, doc) ⇒ Object



79
80
81
82
83
# File 'lib/representable/binding.rb', line 79

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


114
115
116
117
# File 'lib/representable/binding.rb', line 114

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



105
106
107
108
109
# File 'lib/representable/binding.rb', line 105

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)


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

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.



65
66
67
68
69
# File 'lib/representable/binding.rb', line 65

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

#update!(represented, user_options) ⇒ Object

Note: this method is experimental.



151
152
153
154
155
156
# File 'lib/representable/binding.rb', line 151

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

  setup_user_options!(user_options)
  setup_exec_context!
end

#write_fragment(doc, value) ⇒ Object



71
72
73
74
75
76
77
# File 'lib/representable/binding.rb', line 71

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

  return if skipable_empty_value?(value)

  render_fragment(value, doc)
end