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
module Platform
end

class Platform::OS

  def self.calculate_current
    # STUB this would use real data to figure out which class to use
    OpenBSD
  end

  def self.resolve
    missing = []

    klass = calculate_current()
    inst = klass.new

    klass.ancestors.each do |anc|
      break if anc == Platform::OS
      anc.verify! inst, missing
    end

    unless missing.empty?
      puts "Some platform functions were not found:"
      missing.each do |meth|
        puts "  #{meth}"
      end

      unless ENV['PLATFORM_SOFT']
        exit 1
      end
    end
  end
  
  def self.attach(name, *args)
    @methods ||= []
    @methods << name
    begin
      attach_function name, *args
    rescue
    end
  end

  def self.verify!(obj, missing)
    if @methods
      @methods.each do |meth|
        unless obj.respond_to?(meth)
          missing << meth
        end
      end
    end
  end
end

class POSIX < Platform::OS
end

class ModernUnix < POSIX
  attach :lchmod, [:string, :mode_t], :int
  attach :blah, [], :int
end

class BSD < ModernUnix
end

class OpenBSD < BSD
  def lchmod
    raise NotImplementedError, "OpenBSD does not have lchmod"
  end
end


Platform::OS.resolve