Class: Chlog::Logger

Inherits:
Object
  • Object
show all
Defined in:
lib/chlog.rb,
lib/chlog.rb

Constant Summary collapse

TODAY =
Date.today.to_s
UNRELEASED_TITLE =
"## [Unreleased](#) (#{TODAY})"
TEMPLATE =
<<~EOT
  # Changelog

  #{UNRELEASED_TITLE}

  <br>

  ## [Initialize](#) (#{TODAY})

  <br>

  <hr>

  This Changelog is maintained with [chlog](https://github.com/ccmywish/chlog)

EOT
LIST__Feature =
%w[
  new_features  enhancements    bug_fixes
  security      compatibility  deprecations
]
LIST__Main_Category =

New features Enhancements Bug fixes Security Compatibility Deprecations

LIST__Feature.map do
  _1.split('_').join(' ').capitalize
end
LIST__Match_Method =

match_new_features? match_enhancements? match_ …

LIST__Feature.map do
  ('match_' + _1 + '?').to_sym
end
HASH__Order_To_AddTo_Method =

{

  1 => :add_to_new_features,
  2 => :add_to_enhancements,
  ...
}
([1,2,3,4,5,6].zip LIST__Feature.map {|m| ('add_to_' + m).to_sym }).to_h

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeLogger

Returns a new instance of Logger.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/chlog.rb', line 22

def initialize
  require 'highline'
  @highline = HighLine.new

  require 'open3'
  # Prevent current directory is not git directory
  Open3.popen3("git rev-parse --show-toplevel") do |i, o, err, t|
    if err.read.include?("fatal: not a git repository")
      puts "chlog: Not a git directory!" or exit(false)
    else
      @changelog = `git rev-parse --show-toplevel`.chomp + '/CHANGELOG.md'
    end
  end
end

Instance Attribute Details

#highlineObject

存储次标题



16
17
18
# File 'lib/chlog.rb', line 16

def highline
  @highline
end

#logObject

存储次标题



16
17
18
# File 'lib/chlog.rb', line 16

def log
  @log
end

#sub_categoryObject

存储次标题



16
17
18
# File 'lib/chlog.rb', line 16

def sub_category
  @sub_category
end

Instance Method Details

#add_to_bug_fixesObject

main_category_order: 3



346
347
348
# File 'lib/chlog.rb', line 346

def add_to_bug_fixes
  meta_add_to_a_category(@log, 3, "Bug fixes")
end

#add_to_compatibilityObject

main_category_order: 5



356
357
358
# File 'lib/chlog.rb', line 356

def add_to_compatibility
  meta_add_to_a_category(@log, 5, "Compatibility")
end

#add_to_deprecationsObject

The last of order table main_category_order: 6



362
363
364
# File 'lib/chlog.rb', line 362

def add_to_deprecations
  meta_add_to_a_category(@log, 6, "Deprecations")
end

#add_to_enhancementsObject

main category order: 2



341
342
343
# File 'lib/chlog.rb', line 341

def add_to_enhancements
  meta_add_to_a_category(@log, 2, "Enhancements")
end

#add_to_new_featuresObject

main category order: 1



336
337
338
# File 'lib/chlog.rb', line 336

def add_to_new_features
  meta_add_to_a_category(@log, 1, "New features")
end

#add_to_securityObject

main_category_order: 4



351
352
353
# File 'lib/chlog.rb', line 351

def add_to_security
  meta_add_to_a_category(@log, 4, "Security")
end

#ask_user_categoryObject

Help user interactively



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/chlog.rb', line 398

def ask_user_category
  category = @highline.choose do |menu|
    menu.index_color  = :rgb_77bbff
    menu.prompt = "What main category?"
    # return number!!! not string!!!
    menu.choices(*LIST__Main_Category)
  end

  option = LIST__Main_Category.index(category)

  if @sub_category.nil?
    sub = @highline.ask "What sub category? [NIL/sub]"
    case sub
    when '' then @sub_category = nil
    else @sub_category = sub end
  end
  return option
end

#find_main_category_last_list_item_index(lns, main_cat_index, first_lower_order_category_index) ⇒ Object

### New features:

  • xaaaaa

  • xbbbbb

  • xccccc [-> this]



143
144
145
146
147
148
149
150
151
152
153
# File 'lib/chlog.rb', line 143

def find_main_category_last_list_item_index(lns,
                                            main_cat_index,
                                            first_lower_order_category_index)
  mci = main_cat_index
  nci = first_lower_order_category_index

  list_i = lns[mci+2..nci].each_with_index do
    break _2 if _1  !~  /^- .*/
  end
  list_i += mci+2 - 1
end

#first_lower_order_category_index(lns_array, category_order) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/chlog.rb', line 206

def first_lower_order_category_index(lns_array, category_order)

  o = category_order

  nvi = next_version_index(lns_array)

  while o < LIST__Match_Method.size
    lns_array[0...nvi].each_with_index do
      return _2 if send(LIST__Match_Method[o], _1)
    end
    o += 1
  end

  # Next version above
  return (nvi - 2)
end

#generate_changelogObject



60
61
62
63
64
65
66
67
68
# File 'lib/chlog.rb', line 60

def generate_changelog
  file = @changelog
  if File.exist? file
    puts "chlog: Already exists Changelog (#@changelog)" or return false
  else
    File.write(file, TEMPLATE)
    puts "chlog: Generate #@changelog OK!" or return true
  end
end

#get_changelogObject



71
72
73
74
75
76
77
78
# File 'lib/chlog.rb', line 71

def get_changelog
  file = @changelog
  if File.exist? file
    return File.read file
  else
    abort "chlog: No Changelog exists, use 'chlog -g' to generate!"
  end
end

#match_bug_fixes?(str) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/chlog.rb', line 106

def match_bug_fixes?(str)
  str =~ /^### Bug fixes:/
end

#match_compatibility?(str) ⇒ Boolean

Returns:

  • (Boolean)


114
115
116
# File 'lib/chlog.rb', line 114

def match_compatibility?(str)
  str =~ /^### Compatibility:/
end

#match_deprecations?(str) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/chlog.rb', line 118

def match_deprecations?(str)
  str =~ /^### Deprecations:/
end

#match_enhancements?(str) ⇒ Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/chlog.rb', line 102

def match_enhancements?(str)
  str =~ /^### Enhancements:/
end

#match_new_features?(str) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/chlog.rb', line 98

def match_new_features?(str)
  str =~ /^### New features:/
end

#match_security?(str) ⇒ Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/chlog.rb', line 110

def match_security?(str)
  str =~ /^### Security:/
end

#match_unreleased?(str) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/chlog.rb', line 85

def match_unreleased?(str)
  str =~ /^## \[Unreleased\]\(.*\) \(\d{4}-\d\d-\d\d\)/
end

#match_unreleased_fail!(str) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/chlog.rb', line 89

def match_unreleased_fail!(str)
  unless match_unreleased?(str)
    puts  "chlog: Unmatched format with chlog"
    puts
    # "#{lns[1][1..]}"
    abort "Unreleased version must be the third line"
  end
end

#meta_add_to_a_category(log, main_category_order, category) ⇒ Object

A meta function: do the real work other 6 functions delegate

This function detect the main category, and then handle the sub category.



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/chlog.rb', line 228

def meta_add_to_a_category(log, main_category_order, category)

    content = get_changelog
    lns = content.lines

    match_unreleased_fail!(lns[2])

    nvi = next_version_index(lns)
    # To find the existing category line
    main_cat_i = lns[0...nvi].each_with_index do
      # Adjust to index of the order table
      break _2 if send(LIST__Match_Method[main_category_order-1], _1)
    end

    #
    # Always update to latest time when making a log
    #
    # We must add a "\n" because every element of the array
    #   is a sentence with a trailing newline, then they can
    #   be 'joined' to a working long string
    #
    lns[2] = UNRELEASED_TITLE + "\n"

    f_l_o_c_i = first_lower_order_category_index(lns, main_category_order)

    if main_cat_i.class != Integer
    ################################################################################
    # The main category not exists
    ################################################################################


      ########################################
      if @sub_category

      # Because the main category not exists,
      #   nor does the sub category
      #
      sub_cat_i = f_l_o_c_i
      to_wr = lns[0...sub_cat_i].join + "### #{category}:\n\n" + "**#{@sub_category}**\n\n" + '  - ' + log + "\n\n"
      File.write(@changelog, to_wr + lns[sub_cat_i..].join)

      puts "chlog: Add log to #{category}/#{@sub_category}"
      return
      end # end of if @sub_category
      ########################################

      # situation: no sub category

      # Not need adjust to the index of the order table
      log_loc = f_l_o_c_i
      puts "chlog: Add '#{category}' category"
      to_wr = lns[0...(log_loc)].join + "### #{category}:\n\n" + '- ' + log + "\n"
      File.write(@changelog, to_wr + lns[log_loc-1..].join)

  else
  ################################################################################
  # The main category exists
  ################################################################################


    ########################################
    if @sub_category

    # from first list item to next main cat
    #   search if sub cat already exists
    sub_cat_i = lns[main_cat_i+2...f_l_o_c_i].each_with_index do
      break _2 if _1 =~ /^\*\*#{@sub_category}\*\*/
    end

    if !sub_cat_i.is_a?(Integer)
    # the sub category not exists

      sub_cat_i = 2 + find_main_category_last_list_item_index(lns,main_cat_i,f_l_o_c_i)
      to_wr = lns[0...sub_cat_i].join + "**#{@sub_category}**\n\n" + '  - ' + log + "\n\n"
      File.write(@changelog, to_wr + lns[sub_cat_i..].join)
    else
    # the sub category exists

      sub_cat_i +=  main_cat_i+2
      to_wr = lns[0..sub_cat_i+1].join + '  - ' + log + "\n"
      File.write(@changelog, to_wr + lns[sub_cat_i+2..].join)
    end

    puts "chlog: Add log to #{category}/#{@sub_category}"
    return
    end # end of if @sub_category
    ########################################



    # situation: no sub category

    to_wr = lns[0..main_cat_i+1].join + '- ' + log + "\n"

    # main category list should be separated with
    # sub category
    if lns[main_cat_i+2] =~ /\*\*.*/
      to_wr += "\n"
    end
    File.write(@changelog, to_wr + lns[main_cat_i+2..].join)
  end

  puts "chlog: Add log to #{category}"
end

#next_category_index(lns_array) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/chlog.rb', line 128

def next_category_index(lns_array)
  nci = lns_array[3...nvi].each_with_index {break _2 if _1.start_with?("### ") }

  # The not match return value is not nil!! But an array!!
  if nci.is_a(Integer) then nci += 3
  else nil end
end

#next_version_index(lns_array) ⇒ Object



123
124
125
126
# File 'lib/chlog.rb', line 123

def next_version_index(lns_array)
  nvi = lns_array[3..].each_with_index {break _2 if _1.start_with?("## [") }
  nvi += 3
end

#release_new_version(ver) ⇒ Object

Release a version



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/chlog.rb', line 367

def release_new_version(ver)
  if ver.nil?
    puts "chlog: No version supplied!"; puts; abort "Use chlog -r <version>!"
  end

  if !ver.downcase.start_with?('v') and ver[0].match? /\d/
    ver = 'v' + ver
  end

  content = get_changelog
  lns = content.lines

  match_unreleased_fail!(lns[2])

  header = <<~EOF
    # Changelog

    ## [Unreleased](#) (#{TODAY})

    <br>

  EOF

  new_version = "## [#{ver}](#) (#{TODAY})\n"
  new_cont = header + new_version + lns[3..].join('')
  File.write(@changelog, new_cont)
  puts "chlog: Release #{ver} in Changelog!" or return true
end

#take_action(action) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/chlog.rb', line 189

def take_action(action)
  options = "nebscd"

=begin
  {
    "-n" => "new_features", "-e" => "enhancements",  "-b" => "bug_fixes",
    "-s" => "security",     "-c" => "compatibility", "-d" => "deprecations"
  }
=end
  action_table = options.chars.map do |op|
    '-' + op
  end.zip(LIST__Feature).to_h

  public_send "add_to_#{action_table[action]}"
end