File: proxy.rb

package info (click to toggle)
ruby-configurate 0.0.8-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 144 kB
  • ctags: 55
  • sloc: ruby: 666; makefile: 5
file content (84 lines) | stat: -rw-r--r-- 2,355 bytes parent folder | download
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
module Configurate
  # Proxy object to support nested settings
  #
  # *Cavehats*: Since this object is always true, adding a +?+ at the end
  # returns the value, if found, instead of the proxy object.
  # So instead of +if settings.foo.bar+ use +if settings.foo.bar?+
  # to check for boolean values, +if settings.foo.bar.nil?+ to
  # check for nil values and of course you can do +if settings.foo.bar.present?+ to check for
  # empty values if you're in Rails. Call {#get} to actually return the value,
  # commonly when doing +settings.foo.bar.get || "default"+. Also don't
  # use this in case statements since +Module#===+ can't be fooled, again
  # call {#get}.
  #
  # If a setting ends with +=+ it's too called directly, just like with +?+.
  class Proxy < BasicObject
    # @param lookup_chain [#lookup]
    def initialize lookup_chain
      @lookup_chain = lookup_chain
      @setting_path = SettingPath.new
    end
    
    def !
      !target
    end
    
    [:!=, :==, :eql?].each do |method|
      define_method method do |other|
        target.public_send method, target_or_object(other)
      end
    end
    
    def _proxy?
      true
    end
    
    def respond_to? method, include_private=false
      method == :_proxy? || target_respond_to?(method, include_private)
    end
    
    def send *args, &block
      __send__(*args, &block)
    end
    alias_method :public_send, :send
    
    def method_missing setting, *args, &block
      return target.public_send(setting, *args, &block) if target_respond_to? setting

      @setting_path << setting
      
      return target(*args) if @setting_path.is_question_or_setter?
      
      self
    end
    
    # Get the setting at the current path, if found.
    # (see LookupChain#lookup)
    def target *args
      return if @setting_path.empty?

      @lookup_chain.lookup @setting_path, *args
    end
    alias_method :get, :target
    
    private
    COMMON_KEY_NAMES = [:key, :method]

    def target_respond_to? setting, include_private=false
      return false if COMMON_KEY_NAMES.include? setting

      value = target
      return false if proxy? value

      value.respond_to? setting, include_private
    end

    def proxy? obj
      obj.respond_to?(:_proxy?) && obj._proxy?
    end

    def target_or_object obj
      proxy?(obj) ? obj.target : obj
    end
  end
end