Class: BuildpackSupport::FilteringPathname

Inherits:
Object
  • Object
show all
Defined in:
lib/buildpack_support/filtering_pathname.rb

Overview

This class conforms to the interface of Pathname, but filters the set of files that can be accessed and does not support Pathname‘s class methods. This class also provides a glob instance method which filters its output.

If a Pathname method which mutates the file system is called, it will throw an exception unless the instance is created as mutable.

If the underlying filesystem is modified once an instance of this path has been created, the view provided by the instance will not change unless a file or directory allowed by the instance’s filter is created, modified, or deleted.

Instance Method Summary collapse

Constructor Details

#initialize(pathname, filter, mutable) ⇒ FilteringPathname

Create a FilteringPathname which behaves like the given pathname, but which applies the given filter to all files.

The filesystem underpinning the given pathname must not contain a file or directory whose name is the name of the given pathname with ‘.nil’ appended to it. This must be true for the lifetime of the FilteringPathname.

The filter is applied to files which are accessed via the given pathname. If the filter returns true for a particular pathname, the pathname behaves normally for this instance. If the filter returns false for a particular pathname, the pathname behaves as if it does not exist.

Note that the filter must obey the following rule: if the filter accepts Pathnames p and r, where p is a parent directory of r, then the filter must accept every Pathname q where p is a parent directory of q and q is a parent directory of r. FilteringPathname does not check that the filter obeys this rule.

The FilteringPathname may be immutable in which case calling a mutator method causes an exception to be thrown. Alternatively, the FilteringPathname may be mutable in which case calling a mutator method may mutate the file system. The results of mutating the file system will be subject to filtering by the given filter.

Parameters:

  • pathname (Pathname)

    the Pathname which is to be filtered

  • filter (Proc)

    a lambda which takes a Pathname and returns either true (to ‘keep’ the pathname) or false (to filter out the pathname). Defaults to keeping everything

  • mutable (Boolean)

    true if and only if the FilteringPathname may be used to mutate the file system



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/buildpack_support/filtering_pathname.rb', line 54

def initialize(pathname, filter, mutable)
  fail 'Non-absolute pathname' unless pathname.absolute?

  @pathname = pathname
  @filter   = filter
  @mutable  = mutable

  @non_existent = Pathname.new "#{pathname}.nil"
  check_file_does_not_exist @non_existent

  @delegated_pathname = filter(@pathname) ? @pathname : @non_existent
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object (private)



195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/buildpack_support/filtering_pathname.rb', line 195

def method_missing(method, *args)
  check_mutable if MUTATORS.member? method
  if block_given?
    result = delegate.send(method, *args) do |*values|
      converted_values = values.map { |value| convert_if_necessary(value) }.compact
      yield(*converted_values) unless converted_values.empty?
    end
  else
    result = delegate.send(method, *args)
  end
  convert_result_if_necessary(result)
end

Instance Method Details

#+(other) ⇒ Object

See Also:

  • Pathname.


87
88
89
# File 'lib/buildpack_support/filtering_pathname.rb', line 87

def +(other)
  filtered_pathname(@pathname + other)
end

#<=>(other) ⇒ Object

See Also:

  • Pathname.


68
69
70
# File 'lib/buildpack_support/filtering_pathname.rb', line 68

def <=>(other)
  @pathname <=> comparison_target(other)
end

#==(other) ⇒ Object

See Also:

  • Pathname.


73
74
75
# File 'lib/buildpack_support/filtering_pathname.rb', line 73

def ==(other)
  @pathname == comparison_target(other)
end

#===(other) ⇒ Object

See Also:

  • Pathname.


78
79
80
# File 'lib/buildpack_support/filtering_pathname.rb', line 78

def ===(other)
  @pathname === comparison_target(other) # rubocop:disable CaseEquality
end

#children(with_directory = true) ⇒ Object

See Also:

  • Pathname.


113
114
115
116
117
118
119
# File 'lib/buildpack_support/filtering_pathname.rb', line 113

def children(with_directory = true)
  if with_directory
    super # delegate to method_missing
  else
    visible delegate.children(false)
  end
end

#each_child(with_directory = true, &block) ⇒ Object

See Also:

  • Pathname.


122
123
124
125
126
127
128
# File 'lib/buildpack_support/filtering_pathname.rb', line 122

def each_child(with_directory = true, &block)
  if with_directory
    super # delegate to method_missing
  else
    delegate_and_yield_visible(:each_child, false, &block)
  end
end

#each_entry(&block) ⇒ Object

See Also:

  • Pathname.


92
93
94
# File 'lib/buildpack_support/filtering_pathname.rb', line 92

def each_entry(&block)
  delegate_and_yield_visible(:each_entry, &block)
end

#entriesObject

See Also:

  • Pathname.


97
98
99
# File 'lib/buildpack_support/filtering_pathname.rb', line 97

def entries
  visible delegate.entries
end

#glob(flags = 0) ⇒ Object

Execute this FilteringPathname as a glob.



131
132
133
134
135
136
137
138
139
140
# File 'lib/buildpack_support/filtering_pathname.rb', line 131

def glob(flags = 0)
  if block_given?
    Pathname.glob(@pathname, flags) do |file|
      yield filtered_pathname(file) if visible file
    end
  else
    result = Pathname.glob(@pathname, flags)
    convert_result_if_necessary(result)
  end
end

#open(mode = nil, *args, &block) ⇒ Object

See Also:

  • Pathname.


102
103
104
105
# File 'lib/buildpack_support/filtering_pathname.rb', line 102

def open(mode = nil, *args, &block)
  check_mutable if mode =~ /[wa]/
  delegate.open(mode, *args, &block)
end

#to_sObject

See Also:

  • Pathname.


108
109
110
# File 'lib/buildpack_support/filtering_pathname.rb', line 108

def to_s
  @pathname.to_s
end