Module: Tilt::CLI

Defined in:
lib/tilt/cli.rb

Class Method Summary collapse

Class Method Details

.run(argv: ARGV, stdout: $stdout, stdin: $stdin, stderr: $stderr, script_name: File.basename($0)) ⇒ Object

Backbone of the tilt command line utility. Allows mocking input/output for simple testing. Returns program exit code.



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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/tilt/cli.rb', line 40

def self.run(argv: ARGV, stdout: $stdout, stdin: $stdin, stderr: $stderr, script_name: File.basename($0))
  pattern = nil
  layout = nil
  locals = {}
  abort = proc do |msg|
    stderr.puts msg
    return 1
  end

  OptionParser.new do |o|
    o.program_name = script_name

    # list all available template engines
    o.on("-l", "--list") do
      groups = {}
      Tilt.lazy_map.each do |pattern,engines|
        engines.each do |engine,|
          engine = engine.split('::').last.sub(/Template\z/, '')
          (groups[engine] ||= []) << pattern
        end
      end
      groups.sort { |(k1,v1),(k2,v2)| k1 <=> k2 }.each do |engine,files|
        stdout.printf "%-20s %s\n", engine, files.sort.join(', ')
      end
      return 0
    end

    # the template type / pattern
    o.on("-t", "--type=PATTERN", String) do |val|
      abort.("unknown template type: #{val}") unless Tilt[val]
      pattern = val
    end

    # pass template output into the specified layout template
    o.on("-y", "--layout=FILE", String)  do |file|
      paths = [file, "~/.tilt/#{file}", "/etc/tilt/#{file}"]
      layout = paths.
        map  { |p| File.expand_path(p) }.
        find { |p| File.exist?(p) }
      abort.("no such layout: #{file}") if layout.nil?
    end

    # define a local variable
    o.on("-D", "--define=PAIR", String) do |pair|
      key, value = pair.split(/[=:]/, 2)
      locals[key.to_sym] = value
    end

    # define local variables from YAML or JSON
    o.on("-d", "--define-file=FILE", String) do |file|
      require 'yaml'
      abort.("no such define file: #{file}") unless File.exist? file
      hash = File.open(file, 'r:bom|utf-8') { |f| YAML.load(f.read) }
      abort.("vars must be a Hash, not instance of #{hash.class}") unless hash.is_a?(Hash)
      hash.each { |key, value| locals[key.to_sym] = value }
    end

    # define local variables using a Ruby hash
    o.on("--vars=RUBY") do |ruby|
      hash = eval(ruby)
      abort.("vars must be a Hash, not instance of #{hash.class}") unless hash.is_a?(Hash)
      hash.each { |key, value| locals[key.to_sym] = value }
    end

    o.on_tail("-h", "--help") do
      stdout.puts USAGE
      return 0
    end
  end.parse!(argv)

  file = argv.first || '-'
  pattern = file if pattern.nil?
  abort.("template type not given. see: #{script_name} --help") if ['-', ''].include?(pattern)

  engine = Tilt[pattern]
  abort.("template engine not found for: #{pattern}") unless engine

  template =
    engine.new(file) {
      if file == '-'
        stdin.read
      else
        File.read(file)
      end
    }
  output = template.render(self, locals)

  # process layout
  output = Tilt.new(layout).render(self, locals) { output } if layout

  stdout.write(output)

  0
end