File: cli.rb

package info (click to toggle)
ruby-tilt 2.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 648 kB
  • sloc: ruby: 4,998; makefile: 7
file content (134 lines) | stat: -rw-r--r-- 4,190 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
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
134
# frozen_string_literal: true
require_relative '../tilt'
require 'optparse'

module Tilt::CLI
  USAGE = (<<USAGE).freeze
Usage: tilt <options> <file>
Process template <file> and write output to stdout. With no <file> or
when <file> is '-', read template from stdin and use the --type option
to determine the template's type.

Options
  -l, --list                List template engines + file patterns and exit
  -t, --type=<pattern>      Use this template engine; required if no <file>
  -y, --layout=<file>       Use <file> as a layout template

  -D<name>=<value>          Define variable <name> as <value>
  -d, --define-file=<file>  Load YAML from <file> and use for variables
  --vars=<ruby>             Evaluate <ruby> to Hash and use for variables

  -h, --help                Show this help message

Convert markdown to HTML:
  $ tilt foo.markdown > foo.html

Process ERB template:
  $ echo "Answer: <%= 2 + 2 %>" | tilt -t erb
  Answer: 4

Define variables:
  $ echo "Answer: <%= 2 + n %>" | tilt -t erb --vars="{:n=>40}"
  Answer: 42
  $ echo "Answer: <%= 2 + n.to_i %>" | tilt -t erb -Dn=40
  Answer: 42
USAGE
  private_constant :USAGE

  # Backbone of the tilt command line utility. Allows mocking input/output
  # for simple testing. Returns program exit code.
  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
end