Module: Packable::Extensions::IO

Defined in:
lib/packable/extensions/io.rb

Constant Summary collapse

SEEKABLE_API =

Methods supported by seekable streams.

%i[pos pos= seek rewind].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



7
8
9
10
11
12
13
14
# File 'lib/packable/extensions/io.rb', line 7

def self.included(base) #:nodoc:
  base.__send__(:alias_method, :read_without_packing, :read)
  base.__send__(:alias_method, :read, :read_with_packing)
  base.__send__(:alias_method, :write_without_packing, :write)
  base.__send__(:alias_method, :write, :write_with_packing)
  base.__send__(:alias_method, :each_without_packing, :each)
  base.__send__(:alias_method, :each, :each_with_packing)
end

Instance Method Details

#>>(options) ⇒ Object

Usage:

io >> Class
io >> [Class, options]
io >> :shortcut


47
48
49
50
51
52
53
54
55
56
57
# File 'lib/packable/extensions/io.rb', line 47

def >> (options)
  r = []
  class << r
    attr_accessor :stream
    def >> (options)
      self << stream.read(options)
    end
  end
  r.stream = self
  r >> options
end

#each_with_packing(*options, &block) ⇒ Object



77
78
79
80
81
# File 'lib/packable/extensions/io.rb', line 77

def each_with_packing(*options, &block)
  return each_without_packing(*options, &block) if options.empty? || (Integer === options.first) || (String === options.first) || !seekable?
  return self.to_enum(__method__, *options) unless block_given?
  yield read(*options) until eof?
end

#pack_and_write(*arg) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/packable/extensions/io.rb', line 107

def pack_and_write(*arg)
  original_pos = pos
  Packable::Packers.to_object_option_list(*arg).each do |obj, options|
    if options[:write_packed]
      options[:write_packed].bind(obj).call(self)
    else
      obj.write_packed(self, options)
    end
  end
  pos - original_pos
end

#packedObject

Returns (or yields) a modified IO object that will always pack/unpack when writing/reading.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/packable/extensions/io.rb', line 60

def packed
  packedio = clone
  packedio.set_encoding("ascii-8bit") if packedio.respond_to? :set_encoding
  class << packedio
    def << (arg)
      arg = [arg, :default] unless arg.instance_of?(::Array)
      pack_and_write(*arg)
      self
    end
    def packed
      block_given? ? yield(self) : self
    end
    alias_method :write, :pack_and_write #bypass test for argument length
  end
  block_given? ? yield(packedio) : packedio
end

#pos_change(&block) ⇒ Object

Returns the change in io.pos caused by the block. Has nothing to do with packing, but quite helpful and so simpleā€¦



37
38
39
40
41
# File 'lib/packable/extensions/io.rb', line 37

def pos_change(&block)
  delta =- pos
  yield
  delta += pos
end

#read_exactly(n) ⇒ Object

returns a string of exactly n bytes, or else raises an EOFError

Raises:

  • (EOFError)


100
101
102
103
104
105
# File 'lib/packable/extensions/io.rb', line 100

def read_exactly(n)
  return "" if n.zero?
  s = read_without_packing(n)
  raise EOFError if s.nil? || s.length < n
  s
end

#read_with_packing(*arg) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/packable/extensions/io.rb', line 87

def read_with_packing(*arg)
  return read_without_packing(*arg) if arg.empty? || arg.first.nil? || arg.first.is_a?(Numeric) || !seekable?
  values = Packable::Packers.to_class_option_list(*arg).map do |klass, options, original|
    if options[:read_packed]
      options[:read_packed].call(self)
    else
      klass.read_packed(self, options)
    end
  end
  return values.size > 1 ? values : values.first
end

#seekable?Boolean

Check whether can seek without errors.

Returns:

  • (Boolean)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/packable/extensions/io.rb', line 20

def seekable?
  if !defined?(@seekable)
    @seekable =
      # The IO class throws an exception at runtime if we try to change
      # position on a non-regular file.
      if respond_to?(:stat)
        stat.file?
      else
        # Duck-type the rest of this.
        SEEKABLE_API.all? { |m| respond_to?(m) }
      end
  end
  @seekable
end

#write_with_packing(*arg) ⇒ Object



83
84
85
# File 'lib/packable/extensions/io.rb', line 83

def write_with_packing(*arg)
  (arg.length <= 1 || !seekable?) ? write_without_packing(*arg) : pack_and_write(*arg)
end