File: packers.rb

package info (click to toggle)
ruby-packable 1.3.14-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 204 kB
  • sloc: ruby: 609; makefile: 4
file content (106 lines) | stat: -rw-r--r-- 2,741 bytes parent folder | download | duplicates (2)
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
102
103
104
105
106
module Packable

  # Packers for any packable class.
  class Packers < Hash
    SPECIAL = [:default, :merge_all].freeze

    # Usage:
    #   PackableClass.packers.set :shortcut, :option => value, ...
    #   PackableClass.packers { |p| p.set...; p.set... }
    #   PackableClass.packers.set :shortcut, :another_shortcut
    #   PackableClass.packers.set :shortcut do |packer|
    #     packer.write{|io| io << self.something... }
    #     packer.read{|io| Whatever.new(io.read(...)) }
    #   end
    def set(key, options_or_shortcut={})
      if block_given?
        packer = FilterCapture.new options_or_shortcut
        yield packer
      end
      self[key] = options_or_shortcut
      self
    end

    def initialize(klass) #:nodoc:
      @klass = klass
    end

    def lookup(key) #:nodoc:
      k = @klass
      begin
        if found = Packers.for(k)[key]
          return found
        end
        k = k.superclass
      end while k
      SPECIAL.include?(key) ? {} : raise("Unknown option #{key} for #{@klass}")
    end

    def finalize(options) #:nodoc:
      options = lookup(options) while options.is_a? Symbol
      lookup(:merge_all).merge(options)
    end

    @@packers_for_class = Hash.new{|h, klass| h[klass] = Packers.new(klass)}

    # Returns the configuration for the given +klass+.
    def self.for(klass)
      @@packers_for_class[klass]
    end

    def self.to_class_option_list(*arg) #:nodoc:
      r = []
      until arg.empty? do
        k, options = original = arg.shift
        k, options = global_lookup(k) if k.is_a? Symbol
        raise TypeError, "Expected a class or symbol: #{k.inspect}" unless k.instance_of? Class
        options ||= arg.first.is_a?(Hash) ? arg.shift.tap{|o| original = [original, o]} : :default
        r << [k, k.packers.finalize(options), original]
      end
      r
    end

    def self.to_object_option_list(*arg) #:nodoc:
      r=[]
      until arg.empty? do
        obj = arg.shift
        options = case arg.first
        when Hash, Symbol
          arg.shift
        else
          :default
        end
        r << [obj, obj.class.packers.finalize(options)]
      end
      r
    end

  private
    def self.global_lookup(key) #:nodoc:
      @@packers_for_class.each do |klass, packers|
        if options = packers[key]
          return [klass, options]
        end
      end
      raise "Couldn't find packing option #{key}"
    end

  end

  # Use to capture the blocks given to read/write
  class FilterCapture #:nodoc:
    attr_accessor :options
    def initialize(options)
      self.options = options
    end

    def read(&block)
      options[:read_packed] = block
    end

    def write(&block)
      options[:write_packed] = block.unbind
    end
  end

end