Class: Howzit::Topic

Inherits:
Object
  • Object
show all
Defined in:
lib/howzit/topic.rb

Overview

Topic Class

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(title, content) ⇒ Topic

Initialize a topic object

Parameters:

  • title (String)

    The topic title

  • content (String)

    The raw topic content



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/howzit/topic.rb', line 18

def initialize(title, content)
  @title = title
  @content = content
  @parent = nil
  @nest_level = 0
  @named_args = {}
  arguments

  @tasks = gather_tasks
  @results = { total: 0, success: 0, errors: 0, message: ''.c }
end

Instance Attribute Details

#contentObject

Returns the value of attribute content.



8
9
10
# File 'lib/howzit/topic.rb', line 8

def content
  @content
end

#named_argsObject (readonly)

Returns the value of attribute named_args.



10
11
12
# File 'lib/howzit/topic.rb', line 10

def named_args
  @named_args
end

#parent=(value) ⇒ Object (writeonly)

Sets the attribute parent

Parameters:

  • value

    the value to set the attribute parent to.



6
7
8
# File 'lib/howzit/topic.rb', line 6

def parent=(value)
  @parent = value
end

#postreqsObject (readonly)

Returns the value of attribute postreqs.



10
11
12
# File 'lib/howzit/topic.rb', line 10

def postreqs
  @postreqs
end

#prereqsObject (readonly)

Returns the value of attribute prereqs.



10
11
12
# File 'lib/howzit/topic.rb', line 10

def prereqs
  @prereqs
end

#resultsObject (readonly)

Returns the value of attribute results.



10
11
12
# File 'lib/howzit/topic.rb', line 10

def results
  @results
end

#tasksObject (readonly)

Returns the value of attribute tasks.



10
11
12
# File 'lib/howzit/topic.rb', line 10

def tasks
  @tasks
end

#titleObject (readonly)

Returns the value of attribute title.



10
11
12
# File 'lib/howzit/topic.rb', line 10

def title
  @title
end

Instance Method Details

#argumentsObject

Get named arguments from title



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/howzit/topic.rb', line 31

def arguments
  return unless @title =~ /\(.*?\) *$/

  a = @title.match(/\((?<args>.*?)\) *$/)
  args = a['args'].split(/ *, */).each(&:strip)

  args.each_with_index do |arg, idx|
    arg_name, default = arg.split(/:/).map(&:strip)

    @named_args[arg_name] = if Howzit.arguments.count >= idx + 1
                              Howzit.arguments[idx]
                            else
                              default
                            end
  end

  @title = @title.sub(/\(.*?\) *$/, '').strip
end

#grep(term) ⇒ Object

Search title and contents for a pattern

Parameters:

  • term (String)

    the search pattern



55
56
57
# File 'lib/howzit/topic.rb', line 55

def grep(term)
  @title =~ /#{term}/i || @content =~ /#{term}/i
end

Output a topic with fancy title and bright white text.

Parameters:

  • options (Hash) (defaults to: {})

    The options

Returns:

  • (Array)

    array of formatted lines



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/howzit/topic.rb', line 132

def print_out(options = {})
  defaults = { single: false, header: true }
  opt = defaults.merge(options)

  output = []
  if opt[:header]
    output.push(@title.format_header)
    output.push('')
  end
  topic = @content.dup
  topic.gsub!(/(?mi)^(`{3,})run([?!]*) *([^\n]*)[\s\S]*?\n\1\s*$/, '@@@run\2 \3') unless Howzit.options[:show_all_code]
  topic.split(/\n/).each do |l|
    case l
    when /@(before|after|prereq|end)/
      next
    when /@include(?<optional>[!?]{1,2})?\((?<action>[^\)]+)\)/
      m = Regexp.last_match.named_captures.symbolize_keys

      if m[:action] =~ / *\[(.*?)\] *$/
        Howzit.named_arguments = @named_args
        Howzit.arguments = Regexp.last_match(1).split(/ *, */).map!(&:render_arguments)
      end

      matches = Howzit.buildnote.find_topic(m[:action].sub(/ *\[.*?\] *$/, ''))

      unless matches.empty?
        i_topic = matches[0]

        rule = '{kKd}'
        color = '{Kyd}'
        option = if i_topic.tasks.empty?
                   ''
                 else
                   optional = m[:optional] =~ /[?!]+/ ? true : false
                   default = m[:optional] =~ /!/ ? false : true
                   if optional
                     default ? " {xKk}[{gbK}Y{xKk}/{dbwK}n{xKk}]{x}#{color}".c : " {xKk}[{dbwK}y{xKk}/{bgK}N{xKk}]{x}#{color}".c
                   else
                     ''
                   end
                 end
        title = "#{opt[:single] ? 'From' : 'Include'} #{i_topic.title}#{option}:"
        options = { color: color, hr: '.', border: rule }
        unless Howzit.inclusions.include?(i_topic)
          output.push("#{'> ' * @nest_level}#{title}".format_header(options))
        end

        if opt[:single] && Howzit.inclusions.include?(i_topic)
          output.push("#{'> ' * @nest_level}#{title} included above".format_header(options))
        elsif opt[:single]
          @nest_level += 1

          output.concat(i_topic.print_out({ single: true, header: false }))
          output.push("#{'> ' * @nest_level}...".format_header(options))
          @nest_level -= 1
        end
        Howzit.inclusions.push(i_topic)
      end
    when /@(?<cmd>run|copy|open|url)(?<optional>[?!]{1,2})?\((?<action>.*?)\) *(?<title>.*?)$/
      m = Regexp.last_match.named_captures.symbolize_keys
      cmd = m[:cmd]
      obj = m[:action]
      title = m[:title].empty? ? obj : m[:title].strip
      title = Howzit.options[:show_all_code] ? obj : title
      optional = m[:optional] =~ /[?!]+/ ? true : false
      default = m[:optional] =~ /!/ ? false : true
      option = if optional
                 default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
               else
                 ''
               end
      icon = case cmd
             when 'run'
               "\u{25B6}"
             when 'copy'
               "\u{271A}"
             when /open|url/
               "\u{279A}"
             end

      output.push("{bmK}#{icon} {bwK}#{title.preserve_escapes}{x}#{option}".c)
    when /(?<fence>`{3,})run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
      m = Regexp.last_match.named_captures.symbolize_keys
      optional = m[:optional] =~ /[?!]+/ ? true : false
      default = m[:optional] =~ /!/ ? false : true
      option = if optional
                 default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
               else
                 ''
               end
      desc = m[:title].length.positive? ? "Block: #{m[:title]}#{option}" : "Code Block#{option}"
      output.push("{bmK}\u{25B6} {bwK}#{desc}{x}\n```".c)
    when /@@@run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
      m = Regexp.last_match.named_captures.symbolize_keys
      optional = m[:optional] =~ /[?!]+/ ? true : false
      default = m[:optional] =~ /!/ ? false : true
      option = if optional
                 default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
               else
                 ''
               end
      desc = m[:title].length.positive? ? "Block: #{m[:title]}#{option}" : "Code Block#{option}"
      output.push("{bmK}\u{25B6} {bwK}#{desc}{x}".c)
    else
      l.wrap!(Howzit.options[:wrap]) if Howzit.options[:wrap].positive?
      output.push(l)
    end
  end
  Howzit.named_arguments = @named_args
  output.push('').map(&:render_arguments)
end

#run(nested: false) ⇒ Object

Handle run command, execute directives in topic



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
# File 'lib/howzit/topic.rb', line 60

def run(nested: false)
  output = []

  cols = begin
    TTY::Screen.columns > 60 ? 60 : TTY::Screen.columns
  rescue StandardError
    60
  end

  if @tasks.count.positive?
    unless @prereqs.empty?
      puts TTY::Box.frame("{by}#{@prereqs.join("\n\n").wrap(cols - 4)}{x}".c, width: cols)
      res = Prompt.yn('Have the above prerequisites been met?', default: true)
      Process.exit 1 unless res

    end

    @tasks.each do |task|
      if task.optional || Howzit.options[:ask]
        note = if task.type == :include
                 task_count = Howzit.buildnote.find_topic(task.action)[0].tasks.count
                 " (#{task_count} tasks)"
               else
                 ''
               end
        q = %({bg}#{task.type.to_s.capitalize} {xw}"{bw}#{task.title}{xw}"#{note}{x}).c
        res = Prompt.yn(q, default: task.default)
        next unless res

      end
      run_output, total, success = task.run

      output.concat(run_output)
      @results[:total] += total

      if success
        @results[:success] += total
      else
        Howzit.console.warn %({bw}\u{2297} {br}Error running task {bw}"#{task.title}"{x}).c

        @results[:errors] += total

        break unless Howzit.options[:force]
      end
    end

    total = "{bw}#{@results[:total]}{by} #{@results[:total] == 1 ? 'task' : 'tasks'}".c
    errors = "{bw}#{@results[:errors]}{by} #{@results[:errors] == 1 ? 'error' : 'errors'}".c
    @results[:message] += if @results[:errors].zero?
                            "{bg}\u{2713} {by}Ran #{total}{x}".c
                          elsif Howzit.options[:force]
                            "{br}\u{2715} {by}Completed #{total} with #{errors}{x}".c
                          else
                            "{br}\u{2715} {by}Ran #{total}, terminated due to error{x}".c
                          end
  else
    Howzit.console.warn "{r}--run: No {br}@directive{xr} found in {bw}#{@title}{x}".c
  end

  output.push(@results[:message]) if Howzit.options[:log_level] < 2 && !nested

  puts TTY::Box.frame("{bw}#{@postreqs.join("\n\n").wrap(cols - 4)}{x}".c, width: cols) unless @postreqs.empty?

  output
end