fronde 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/bin/fronde +15 -30
  3. data/lib/ext/nil_time.rb +25 -0
  4. data/lib/ext/r18n.rb +17 -0
  5. data/lib/ext/time.rb +49 -0
  6. data/lib/fronde/cli/commands.rb +92 -103
  7. data/lib/fronde/cli/data/Rakefile +8 -0
  8. data/lib/fronde/cli/data/config.yml +13 -0
  9. data/lib/fronde/cli/data/gitignore +7 -0
  10. data/lib/fronde/cli/data/zsh_completion +37 -0
  11. data/lib/fronde/cli/helpers.rb +55 -0
  12. data/lib/fronde/cli/opt_parse.rb +143 -0
  13. data/lib/fronde/cli/throbber.rb +99 -0
  14. data/lib/fronde/cli.rb +41 -42
  15. data/lib/fronde/config/data/org-config.el +24 -0
  16. data/lib/fronde/config/{ox-fronde.el → data/ox-fronde.el} +1 -1
  17. data/lib/fronde/config/helpers.rb +80 -0
  18. data/lib/fronde/config/lisp.rb +70 -0
  19. data/lib/fronde/config.rb +135 -99
  20. data/lib/fronde/emacs.rb +23 -20
  21. data/lib/fronde/index/atom_generator.rb +55 -66
  22. data/lib/fronde/index/data/all_tags.org +14 -0
  23. data/lib/fronde/index/data/template.org +22 -0
  24. data/lib/fronde/index/data/template.xml +37 -0
  25. data/lib/fronde/index/org_generator.rb +70 -88
  26. data/lib/fronde/index.rb +56 -82
  27. data/lib/fronde/org/file.rb +287 -0
  28. data/lib/fronde/org/file_extracter.rb +98 -0
  29. data/lib/fronde/org.rb +103 -0
  30. data/lib/fronde/preview.rb +43 -39
  31. data/lib/fronde/slug.rb +27 -0
  32. data/lib/fronde/source/gemini.rb +39 -0
  33. data/lib/fronde/source/html.rb +67 -0
  34. data/lib/fronde/source.rb +204 -0
  35. data/lib/fronde/templater.rb +94 -71
  36. data/lib/fronde/version.rb +1 -1
  37. data/lib/tasks/cli.rake +33 -0
  38. data/lib/tasks/org.rake +62 -42
  39. data/lib/tasks/site.rake +68 -30
  40. data/lib/tasks/sync.rake +41 -21
  41. data/lib/tasks/tags.rake +11 -7
  42. data/locales/en.yml +60 -14
  43. data/locales/fr.yml +68 -14
  44. metadata +53 -110
  45. data/lib/fronde/config/lisp_config.rb +0 -340
  46. data/lib/fronde/config/org-config.el +0 -19
  47. data/lib/fronde/org_file/class_methods.rb +0 -72
  48. data/lib/fronde/org_file/extracter.rb +0 -72
  49. data/lib/fronde/org_file/htmlizer.rb +0 -43
  50. data/lib/fronde/org_file.rb +0 -298
  51. data/lib/fronde/utils.rb +0 -229
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59daab21a7ef37010f30971994ebda28af2c212528205e43c2dae18abe6c510f
4
- data.tar.gz: 89fda0a99813459bdbd2291c91aebe44d3a6c2fb3a6faf4742b7e7036191e5e8
3
+ metadata.gz: 31ed851cf895abccd33ec85ab91459e4310c9716631d096efd89d18fd16bf190
4
+ data.tar.gz: 901e11daea515cff4336f05a13a67604a5d73ca9fc020efb8250b34fbdb72450
5
5
  SHA512:
6
- metadata.gz: de60c2c6254acbe48846e3af209106aeb1f7058a604491e27bbeef1bf32b2c78d1d17e320d47168f086b046ad368b888a5b6933eddf56b7f4471c824c6acaa14
7
- data.tar.gz: 62f6c65db410960e4395bcbbff9bb1918886dfdb9a1c0b9c8f8871f61c285160c1a3edca901619b674b93bce80ba1cc45ce2de6ce74195c4c0f5a72292db1d70
6
+ metadata.gz: 1190105b49652d3bf177602a9ca37906f9a4659416f821734b17b5a49269825726019a6b69ad47b312937d75b362e658b93026003ffc42cd92859b601c9c8e96
7
+ data.tar.gz: 4e34d65345c82cc39237521c2e79365bbe4c23572fa4c4fa7d65e2d5aa7119d095a2956ec569e03c6cb459e7f1f37fe933aac3d2b0fdcefafb69f1cea8ef695b
data/bin/fronde CHANGED
@@ -1,45 +1,30 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'optparse'
5
- require 'r18n-core'
6
- require 'fronde/utils'
7
- require 'fronde/version'
8
- require 'fronde/cli'
9
-
10
- R18n.default_places = File.expand_path('../locales', __dir__)
11
- R18n.set Fronde::Config.get('lang')
4
+ require_relative '../lib/fronde/config'
5
+ require_relative '../lib/fronde/version'
6
+ require_relative '../lib/fronde/cli'
12
7
 
8
+ require 'optparse'
13
9
  optparser = OptionParser.new
14
10
  optparser.version = Fronde::VERSION
15
11
 
16
- Fronde::Utils::FRONDE_OPTIONS.each do |k, opt|
17
- optparser.send(opt[:meth] || :on, *Fronde::Utils.decorate_option(k))
12
+ Fronde::CLI::OptParse::FRONDE_OPTIONS.each do |k, opt|
13
+ optparser.send(opt[:method] || :on, *Fronde::CLI::OptParse.decorate_option(k))
18
14
  end
19
15
 
20
- params = {}
21
- optparser.parse!(into: params)
16
+ params = { verbose: false }
17
+ begin
18
+ optparser.parse!(into: params)
19
+ rescue OptionParser::InvalidArgument => e
20
+ warn e.message
21
+ params.merge!(help: true, recover_from_error: true)
22
+ end
22
23
 
23
24
  if params[:version]
24
25
  warn optparser.ver
25
26
  exit
26
27
  end
27
28
 
28
- if ARGV[0] == 'help'
29
- params[:help] = true
30
- ARGV.shift
31
- end
32
- fronde = Fronde::CLI.new(params)
33
- command = "fronde_#{ARGV[0]}".to_sym
34
- cmd_err = !fronde.respond_to?(command)
35
- if params[:help] || cmd_err
36
- cmd_err = false if params[:help] && !ARGV[0]
37
- fronde.fronde_help(ARGV[0], error: cmd_err)
38
- end
39
- ARGV.shift
40
-
41
- init_cmds = [:fronde_init, :fronde_config, :fronde_update]
42
- unless File.exist?('config.yml') || init_cmds.include?(command)
43
- fronde.fronde_init
44
- end
45
- fronde.send command
29
+ fronde = Fronde::CLI::App.new(params)
30
+ exit fronde.run(ARGV)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A time emulator to handle cases where no time is available
4
+ class NilTime
5
+ def strftime(*)
6
+ ''
7
+ end
8
+
9
+ def xmlschema(_ = 0)
10
+ ''
11
+ end
12
+
13
+ def l18n_short_date_string
14
+ ''
15
+ end
16
+
17
+ def l18n_long_date_string(*)
18
+ ''
19
+ end
20
+
21
+ def l18n_short_date_html
22
+ '<time></time>'
23
+ end
24
+ alias_method :l18n_long_date_html, :l18n_long_date_string
25
+ end
data/lib/ext/r18n.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patch to add a little helper
4
+ module R18nPatch
5
+ refine R18n::Translation do
6
+ def full_datetime_format
7
+ date_fmt = fronde.index.full_date_format(
8
+ date: @locale.full_format
9
+ )
10
+ date_fmt = @locale.year_format.sub('_', date_fmt)
11
+ time_fmt = @locale.time_format.delete('_').strip
12
+ fronde.index.full_date_with_time_format(
13
+ date: date_fmt, time: time_fmt
14
+ )
15
+ end
16
+ end
17
+ end
data/lib/ext/time.rb ADDED
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patch to add some helpers
4
+ module TimePatch
5
+ refine Time do
6
+ # Returns the current Time instance as a localized short string.
7
+ #
8
+ # @return [String] the localized Time string representation
9
+ def l18n_short_date_string
10
+ R18n.l to_date
11
+ end
12
+
13
+ # Format the current Time as a HTML `time` tag showing a short date.
14
+ #
15
+ # @return [String] the HTML `time` tag
16
+ def l18n_short_date_html
17
+ "<time datetime=\"#{xmlschema}\">#{l18n_short_date_string}</time>"
18
+ end
19
+
20
+ def no_time=(value)
21
+ @no_time = value
22
+ end
23
+
24
+ # Returns the current Time instance as a localized long string.
25
+ #
26
+ # @param with_year [Boolean] wether or not the string must contain the
27
+ # year
28
+ # @return [String] the localized Time string representation
29
+ def l18n_long_date_string(with_year: true)
30
+ locale = R18n.get.locale
31
+ long_fmt = R18n.t.fronde.index.full_date_format(
32
+ date: locale.format_date_full(self, year: with_year)
33
+ )
34
+ unless @no_time
35
+ long_fmt = R18n.t.fronde.index.full_date_with_time_format(
36
+ date: long_fmt, time: locale.time_format.delete('_').strip
37
+ )
38
+ end
39
+ locale.strftime(self, long_fmt)
40
+ end
41
+
42
+ # Format the current Time as a HTML `time` tag showing a long date.
43
+ #
44
+ # @return [String] the HTML `time` tag
45
+ def l18n_long_date_html
46
+ "<time datetime=\"#{xmlschema}\">#{l18n_long_date_string}</time>"
47
+ end
48
+ end
49
+ end
@@ -1,125 +1,114 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'helpers'
4
+ require_relative 'opt_parse'
5
+ require_relative '../slug'
6
+ require_relative '../org/file'
7
+
3
8
  module Fronde
4
- # Fronde commands
5
- module CLICommands
6
- def fronde_update
7
- update_config
8
- @rake.options.build_all = true
9
- @rake.invoke_task('org:upgrade')
10
- end
11
- alias_method :fronde_config, :fronde_update
9
+ module CLI
10
+ # Fronde commands
11
+ module Commands
12
+ def fronde_new
13
+ new_dir = @argv.first || 'my_fronde_website'
14
+ FileUtils.mkdir new_dir
15
+ Dir.chdir new_dir
16
+ Helpers.init_config_file @options
17
+ Fronde::CONFIG.reset # Correctly compute various path
18
+ Helpers.init_rakefile
19
+ init_rake
20
+ @rake['org:install'].invoke
21
+ @argv = ['src/index.org']
22
+ fronde_open
23
+ end
12
24
 
13
- def fronde_init
14
- update_config
15
- @rake.options.build_all = true
16
- @rake.invoke_task('org:install')
17
- return if File.exist? 'src/index.org'
18
- Fronde::OrgFile.new('src/index.org', @options).write
19
- fronde_open 'src/index.org'
20
- end
25
+ def fronde_update
26
+ Helpers.init_rakefile
27
+ init_rake
28
+ @rake.options.build_all = true
29
+ @rake['org:upgrade'].invoke
30
+ 0
31
+ end
21
32
 
22
- def fronde_build
23
- @rake.options.build_all = true
24
- task = 'site:build'
25
- task = "#{task}[true]" if @options[:force]
26
- @rake.invoke_task task
27
- end
33
+ def fronde_build
34
+ @rake.options.build_all = true
35
+ @rake['site:build'].invoke @options[:force]
36
+ 0
37
+ end
28
38
 
29
- def fronde_preview
30
- Thread.new do
31
- sleep 1
32
- port = Fronde::Config.get(['preview', 'server_port'], 5000)
33
- uri = "http://127.0.0.1:#{port}/"
34
- current_os = Fronde::Utils.current_os
35
- case current_os
36
- when 'windows'
37
- system 'start', uri
38
- when 'apple'
39
- system 'open', uri
40
- else
41
- system 'gio', 'open', uri
39
+ def fronde_preview
40
+ Thread.new do
41
+ sleep 1
42
+ port = Fronde::CONFIG.get(%w[preview server_port], 5000)
43
+ Helpers.launch_app_for_uri "http://127.0.0.1:#{port}/"
42
44
  end
45
+ @rake['site:preview'].invoke
46
+ 0
43
47
  end
44
- @rake.invoke_task('site:preview')
45
- end
46
48
 
47
- def fronde_open(file_path = ARGV[0])
48
- editor = ENV['EDITOR'] || ENV['VISUAL'] || 'emacs'
49
- cmd = [editor]
50
- if file_path.nil? || !File.file?(file_path)
51
- # file_path may be updated with title given in options
52
- file_path = create_new_file(file_path)
53
- # Only move to the end of file for new file. Let the editor handle
54
- # the best position for already existing files
55
- cmd << '+6'
49
+ def fronde_open
50
+ editor = ENV['EDITOR'] || ENV['VISUAL'] || 'emacs'
51
+ cmd = [editor]
52
+ file_path = @argv.first || Dir.pwd
53
+ unless File.file?(file_path)
54
+ # file_path may be updated with title given in options
55
+ file_path = create_new_file(file_path)
56
+ # Only move to the end of file for new file. Let the editor handle
57
+ # the best position for already existing files
58
+ cmd << '+6'
59
+ end
60
+ cmd << file_path
61
+ (system(*cmd) && 0) || 1
56
62
  end
57
- cmd << file_path
58
- system(*cmd)
59
- end
60
- alias_method :fronde_edit, :fronde_open
61
63
 
62
- def fronde_publish
63
- @rake.invoke_task('sync:push')
64
- end
64
+ def fronde_publish
65
+ @rake['sync:push'].invoke
66
+ 0
67
+ end
65
68
 
66
- def fronde_help(command = 'basic', error: false)
67
- warn R18n.t.fronde.bin.error.no_command if error
68
- cmd_opt = Fronde::Utils.command_options(command)
69
- label = cmd_opt[:label] || command
70
- warn format("%<label>s\n\n", label: R18n.t.fronde.bin.usage(label))
71
- cmd = cmd_opt[:name] || command
72
- if R18n.t.fronde.bin.commands[cmd].translated?
73
- warn format("%<label>s\n\n", label: R18n.t.fronde.bin.commands[cmd])
69
+ def fronde_help
70
+ # Try to find command in next argv, otherwise fallback again.
71
+ @command = @argv.shift || 'basic' if @command == 'help'
72
+ cmd_opt = OptParse.command_options(@command)
73
+ label = cmd_opt[:label] || @command
74
+ warn format("%<label>s\n\n", label: R18n.t.fronde.bin.usage(label))
75
+ cmd = cmd_opt[:name] || @command
76
+ if R18n.t.fronde.bin.commands[cmd].translated?
77
+ warn format("%<label>s\n\n", label: R18n.t.fronde.bin.commands[cmd])
78
+ end
79
+ body = OptParse.help_command_body(cmd)
80
+ warn body unless body == ''
81
+ 0
74
82
  end
75
- warn help_command_body(cmd).join("\n")
76
- exit 1 if error
77
- exit
78
- end
79
83
 
80
- private
84
+ private
81
85
 
82
- def update_config
83
- cnf = @options.merge
84
- cnf.delete(:verbose)
85
- cnf.transform_keys!(&:to_s)
86
- Fronde::Config.save(Fronde::Config.settings.merge(cnf))
87
- end
86
+ def file_name_from_title
87
+ title = @options[:title] || R18n.t.fronde.bin.options.default_title
88
+ # No title, nor a reliable file_path? Better abort
89
+ raise R18n.t.fronde.error.bin.no_file if title == ''
88
90
 
89
- def new_file_name(file_path)
90
- file_path = File.expand_path(file_path || '')
91
- return file_path if file_path[-4..] == '.org'
92
- # file_path seems to be a dir path. Thus we have to create the new
93
- # filename from its title
94
- title = @options[:title]
95
- # No title, nor a reliable file_path? Better abort
96
- return nil if title.nil? || title == ''
97
- filename = "#{Fronde::OrgFile.slug(title)}.org"
98
- File.join file_path, filename
99
- end
91
+ "#{Fronde::Slug.slug(title)}.org"
92
+ end
100
93
 
101
- def create_new_file(file_path)
102
- filename = new_file_name(file_path)
103
- if filename.nil?
104
- warn R18n.t.fronde.bin.error.no_file
105
- exit 1
94
+ def new_file_name(file_path)
95
+ file_path = File.expand_path(file_path)
96
+
97
+ if file_path[-4..] == '.org' && !File.directory?(file_path)
98
+ return file_path
99
+ end
100
+
101
+ # file_path seems to be a dir path. Thus we have to create the new
102
+ # filename from its title
103
+ File.join file_path, file_name_from_title
106
104
  end
107
- FileUtils.mkdir_p File.dirname(filename)
108
- Fronde::OrgFile.new(filename, @options).write
109
- filename
110
- end
111
105
 
112
- def help_command_body(command)
113
- body = [
114
- R18n.t.fronde.bin.options.cmd_title,
115
- Fronde::Utils.summarize_command(command)
116
- ]
117
- return body unless command == 'basic'
118
- body + [
119
- '',
120
- R18n.t.fronde.bin.commands.cmd_title,
121
- Fronde::Utils.list_commands
122
- ]
106
+ def create_new_file(file_path)
107
+ filename = new_file_name(file_path)
108
+ FileUtils.mkdir_p File.dirname(filename)
109
+ Fronde::Org::File.new(filename, @options).write
110
+ filename
111
+ end
123
112
  end
124
113
  end
125
114
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fronde/config'
4
+
5
+ fronde_spec = Gem::Specification.find_by_name 'fronde'
6
+ Dir.glob("#{fronde_spec.gem_dir}/lib/tasks/*.rake").each { |r| import r }
7
+
8
+ task default: 'site:build'
@@ -0,0 +1,13 @@
1
+ ---
2
+ {%- if author %}
3
+ author: {{ author }}
4
+ {%- endif %}
5
+ {%- if lang %}
6
+ lang: {{ lang }}
7
+ {%- endif %}
8
+ sources:
9
+ - path: src
10
+ target: .
11
+ {%- if output == 'gemini' %}
12
+ type: gemini
13
+ {%- endif %}
@@ -0,0 +1,7 @@
1
+ .dir-locals.el
2
+ .ruby-version
3
+ Rakefile
4
+ lib/
5
+ public_gmi/
6
+ public_html/
7
+ var/
@@ -0,0 +1,37 @@
1
+ #compdef fronde
2
+ #autoload
3
+
4
+ {% for command in commands %}
5
+ {%- for option in command.options %}
6
+ {%- if forloop.first %}
7
+ (( $+functions[__fronde_{{ command.name }}] )) ||
8
+ __fronde_{{ command.name }}(){
9
+ _arguments \
10
+ {%- endif %}
11
+ '({{ option.short }} {{ option.long }})'{{ '{' }}{{ option.short}},{{ option.long }}}
12
+ {%- if option.keyword %}':{{ option.keyword }}:'{% endif %}
13
+ {%- if forloop.last %}
14
+ {%- if command.name == 'open' %} \
15
+ '1:file:_files -g \*.org'
16
+ {%- endif %}
17
+ }
18
+ {% else %} \{% endif %}
19
+ {%- endfor %}{% endfor %}
20
+
21
+ (( $+functions[__fronde_help] )) ||
22
+ __fronde_help(){
23
+ _arguments \
24
+ "1:command:(({% for command in commands %}{{ command.name }}\:'{{ command.translation }}' {% endfor %}))"
25
+ }
26
+
27
+ local state
28
+
29
+ _arguments -C \
30
+ '(-)-h[help]' \
31
+ '(-)-V[version]' \
32
+ "1:command:(({% for command in commands %}{{ command.name }}\:'{{ command.translation }}' {% endfor %}))" \
33
+ '*::arg:->args'
34
+
35
+ if [ "$state" = args ]; then
36
+ _call_function ret __fronde_${words[1]}
37
+ fi
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'net/http'
5
+ require 'fileutils'
6
+
7
+ module Fronde
8
+ module CLI
9
+ # Various utilitaries methods
10
+ module Helpers
11
+ def self.init_config_file(config)
12
+ return if File.exist? 'config.yml'
13
+
14
+ output = config[:output] || 'html'
15
+ output = 'gemini' if output == 'gmi'
16
+ data = { 'author' => config[:author],
17
+ 'lang' => config[:lang],
18
+ 'output' => output }
19
+ source = File.expand_path './data/config.yml', __dir__
20
+ template = Liquid::Template.parse(File.read(source))
21
+ File.write('config.yml', template.render(data))
22
+ end
23
+
24
+ def self.init_rakefile
25
+ FileUtils.cp(
26
+ File.expand_path('./data/Rakefile', __dir__),
27
+ 'Rakefile'
28
+ )
29
+ end
30
+
31
+ def self.launch_app_for_uri(uri)
32
+ case current_os
33
+ when 'windows'
34
+ system 'start', uri
35
+ when 'apple'
36
+ system 'open', uri
37
+ else
38
+ system 'gio', 'open', uri
39
+ end
40
+ end
41
+
42
+ # Try to discover the current host operating system.
43
+ #
44
+ # @return [String] either apple, windows or linux (default)
45
+ def self.current_os
46
+ if ENV['OS'] == 'Windows_NT' || RUBY_PLATFORM.include?('cygwin')
47
+ return 'windows'
48
+ end
49
+ return 'apple' if RUBY_PLATFORM.include?('darwin')
50
+
51
+ 'linux'
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fronde
4
+ module CLI
5
+ # Helper code to help build the fronde option parser
6
+ module OptParse
7
+ # @return [Hash] the possible ~fronde~ options and their
8
+ # configuration
9
+ FRONDE_OPTIONS = {
10
+ '-a' => { long: 'author' },
11
+ '-f' => { long: 'force', boolean: true },
12
+ '-h' => { long: 'help', boolean: true, method: :on_tail,
13
+ help: R18n.t.fronde.bin.options.help },
14
+ '-l' => { long: 'lang', keyword: 'LOCALE' },
15
+ '-o' => { long: 'output', keyword: 'FORMAT', choices: %w[gemini html] },
16
+ '-t' => { long: 'title' },
17
+ '-v' => { long: 'verbose', boolean: true, method: :on_tail },
18
+ '-V' => { long: 'version', boolean: true, method: :on_tail,
19
+ help: R18n.t.fronde.bin.options.version }
20
+ }.freeze
21
+
22
+ # TODO: jekyll new [path] / jekyll build / jekyll clean / jekyll serve
23
+ # TODO: hugo new site [path] / hugo / hugo new content / hugo server
24
+ # TODO: zola init [path] / zola build --root path_to_project / zola serve
25
+
26
+ # @return [Hash] the possible ~fronde~ subcommands and their
27
+ # configuration
28
+ FRONDE_COMMANDS = {
29
+ 'new' => { opts: ['-a', '-l', '-o', '-t', '-v'], label: 'new <path>' },
30
+ 'init' => { alias: 'new' },
31
+ 'update' => {},
32
+ 'config' => { alias: 'update' },
33
+ 'preview' => {},
34
+ 'open' => { opts: ['-a', '-l', '-t', '-v'], label: 'open <path>' },
35
+ 'edit' => { alias: 'open' },
36
+ 'build' => { opts: ['-f'] },
37
+ 'publish' => {},
38
+ 'help' => {},
39
+ 'basic' => { opts: ['-h', '-V'], label: '<command>' }
40
+ }.freeze
41
+
42
+ class << self
43
+ # Returns the short and long options specification for a given
44
+ # short option.
45
+ #
46
+ # This method use the {Fronde::CLI::OptParse::FRONDE_OPTIONS}
47
+ # Hash to retrieve corresponding values.
48
+ #
49
+ # @example
50
+ # spec = Fronde::CLI::OptParse.decorate_option('-a')
51
+ # => ['-a AUTHOR', '--author AUTHOR']
52
+ #
53
+ # @param short [String] the short option to decorate
54
+ # @return [Array] the short and long specification for an option
55
+ def decorate_option(short)
56
+ opt = FRONDE_OPTIONS[short]
57
+ long = "--#{opt[:long]}"
58
+ if opt[:boolean]
59
+ config = [short, long]
60
+ else
61
+ key = opt[:keyword] || opt[:long].upcase
62
+ config = [short, format('%<long>s %<key>s', long: long, key: key)]
63
+ end
64
+ config << opt[:choices] if opt[:choices]
65
+ config << opt[:help] if opt[:help]
66
+ config
67
+ end
68
+
69
+ # Returns the ~fronde~ help summary for a given command.
70
+ #
71
+ # @param command [String] the command for which a summary
72
+ # should be given
73
+ # @return [String]
74
+ def summarize_command(command)
75
+ (FRONDE_COMMANDS[command][:opts] || []).map do |k|
76
+ short, long = decorate_option(k)
77
+ opt = FRONDE_OPTIONS[k]
78
+ label = [short, long].join(', ')
79
+ line = [format(' %<opt>s', opt: label).ljust(30)]
80
+ help = opt[:help]
81
+ line << help if help
82
+ choices = opt[:choices]
83
+ line << "(#{choices.join(', ')})" if choices
84
+ line.join(' ')
85
+ end.join("\n")
86
+ end
87
+
88
+ def help_command_body(command)
89
+ command_opts_doc = summarize_command(command)
90
+ return '' if command_opts_doc == ''
91
+
92
+ body = [R18n.t.fronde.bin.options.cmd_title, command_opts_doc]
93
+ if command == 'basic'
94
+ body += ['', R18n.t.fronde.bin.commands.cmd_title, list_commands]
95
+ end
96
+ body.join("\n")
97
+ end
98
+
99
+ # Returns a formatted list of available commands for ~fronde~.
100
+ #
101
+ # @return [String]
102
+ def list_commands
103
+ FRONDE_COMMANDS.filter_map do |cmd, opt|
104
+ next if cmd == 'basic'
105
+
106
+ line = [' ', cmd.ljust(10)]
107
+ if opt.has_key? :alias
108
+ line << R18n.t.fronde.bin.commands.alias(opt[:alias])
109
+ else
110
+ line << R18n.t.fronde.bin.commands[cmd]
111
+ end
112
+ line.join(' ')
113
+ end.join("\n")
114
+ end
115
+
116
+ # Returns the real command name for a given command, which may be
117
+ # an alias.
118
+ #
119
+ # @param command [String] the command to resolve
120
+ # @return [String]
121
+ def resolve_possible_alias(command)
122
+ return 'basic' unless FRONDE_COMMANDS.include?(command)
123
+
124
+ cmd_opt = FRONDE_COMMANDS[command]
125
+ return cmd_opt[:alias] if cmd_opt.has_key?(:alias)
126
+
127
+ command
128
+ end
129
+
130
+ # Returns the given command options.
131
+ #
132
+ # This method will first try to resolve command alias, if any.
133
+ #
134
+ # @param command [String] the command, which options should be returned
135
+ # @return [Hash] the command options
136
+ def command_options(command)
137
+ cmd = resolve_possible_alias command
138
+ FRONDE_COMMANDS[cmd].merge(name: cmd)
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end