File: binding.rb

package info (click to toggle)
ruby-representable 3.0.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 896 kB
  • sloc: ruby: 6,432; makefile: 3
file content (101 lines) | stat: -rw-r--r-- 3,192 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
module Representable
  # The Binding provides methods to read/write the fragment for one property.
  #
  # Actually parsing the fragment from the document happens in Binding#read, everything after that is generic.
  class Binding
    class FragmentNotFound
    end

    def self.build(definition)
      build_for(definition)
    end

    def initialize(definition)
      @definition       = definition
      @name             = @definition.name
      @getter           = @definition.getter
      @setter           = @definition.setter

      setup_exec_context!
    end

    attr_reader :name, :getter, :setter
    extend Uber::Delegates
    delegates :@definition, :has_default?, :representable?, :array?, :typed?

    # Single entry points for rendering and parsing a property are #compile_fragment
    # and #uncompile_fragment in Mapper.

    module Deprecatable
      # Retrieve value and write fragment to the doc.
      def compile_fragment(options)
        render_pipeline(nil, options).(nil, options)
      end

      # Parse value from doc and update the model property.
      def uncompile_fragment(options)
        parse_pipeline(options[:doc], options).(options[:doc], options)
      end
    end
    include Deprecatable

    module EvaluateOption
      def evaluate_option(name, input, options)
        proc = self[name]
        # puts "@@@@@ #{self.inspect}, #{name}...... #{self[name]}"
        proc.(send(:exec_context, options), options.merge(user_options: options[:options][:user_options], input: input)) # from Uber::Options::Value. # NOTE: this can also be the Proc object if it's not wrapped by Uber:::Value.
      end
    end
    include EvaluateOption

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

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

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

    attr_accessor :cached_representer

    require "representable/pipeline_factories"
    include Factories

  private

    def setup_exec_context!
      @exec_context = ->(options) { options[:represented] }     unless self[:exec_context]
      @exec_context = ->(options) { self }                      if self[:exec_context] == :binding
      @exec_context = ->(options) { options[:decorator] }       if self[:exec_context] == :decorator
    end

    def exec_context(options)
      @exec_context.(options)
    end

    def parse_pipeline(input, options)
      @parse_pipeline ||= pipeline_for(:parse_pipeline, input, options) { Pipeline[*parse_functions] }
    end

    def render_pipeline(input, options)
      @render_pipeline ||= pipeline_for(:render_pipeline, input, options) { Pipeline[*render_functions] }
    end

    # generics for collection bindings.
    module Collection
      def skipable_empty_value?(value)
        # TODO: this can be optimized, again.
        return true if value.nil? and not self[:render_nil] # FIXME: test this without the "and"
        return true if self[:render_empty] == false and value and value.size == 0  # TODO: change in 2.0, don't render emtpy.
      end
    end
  end

  class DeserializeError < RuntimeError
  end
end