neruda 0.1.0 → 0.2.2

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.
@@ -7,6 +7,7 @@ require 'neruda/org_file/htmlizer'
7
7
  require 'neruda/org_file/extracter'
8
8
  require 'neruda/org_file/class_methods'
9
9
  require 'neruda/index'
10
+ require 'neruda/version'
10
11
 
11
12
  module Neruda
12
13
  # Handles org files.
@@ -19,6 +20,10 @@ module Neruda
19
20
  # the ~#+title:~ header.
20
21
  attr_reader :title
21
22
 
23
+ # @return [String] the subtitle of the current org document, taken
24
+ # from the ~#+subtitle:~ header.
25
+ attr_reader :subtitle
26
+
22
27
  # @return [DateTime] the date and time of the current org document,
23
28
  # taken from the ~#+date:~ header.
24
29
  attr_reader :date
@@ -40,6 +45,10 @@ module Neruda
40
45
  # taken from the ~#+keywords:~ header.
41
46
  attr_reader :keywords
42
47
 
48
+ # @return [String] the description of this org document, taken from
49
+ # the ~#+description:~ header.
50
+ attr_reader :excerpt
51
+
43
52
  # The locale of the current org document, taken from the
44
53
  # ~#+language:~ header.
45
54
  #
@@ -61,9 +70,8 @@ module Neruda
61
70
  # settings and the above {#html_file @html_file} attribute.
62
71
  attr_reader :url
63
72
 
64
- # @return [String] the description of this org document, taken from
65
- # the ~#+description:~ header.
66
- attr_reader :excerpt
73
+ # @return [String] the project owning this document.
74
+ attr_reader :project
67
75
 
68
76
  extend Neruda::OrgFileClassMethods
69
77
 
@@ -96,21 +104,25 @@ module Neruda
96
104
  # o.title
97
105
  # => "New file"
98
106
  #
99
- # @param file_name [String] path to the corresponding org mode file
100
- # @param opts [Hash] optional data to initialize new org file
101
- # @option opts [String] title ('') the title of the new org file
107
+ # @param file_name [String] path to the corresponding Org file
108
+ # @param opts [Hash] optional data to initialize new Org file
109
+ # @option opts [String] title ('') the title of the new Org file
102
110
  # @option opts [String] author (system user or '') the author of the
103
111
  # document
104
112
  # @option opts [Boolean] verbose (false) if the
105
113
  # {Neruda::OrgFileHtmlizer#publish publish} method should output
106
114
  # emacs process messages
115
+ # @option opts [String] project the project owning this file
116
+ # must be stored
107
117
  # @return [Neruda::OrgFile] the new instance of Neruda::OrgFile
108
118
  def initialize(file_name, opts = {})
109
119
  file_name = nil if file_name == ''
110
120
  @file = file_name
111
- @html_file = Neruda::OrgFile.html_file @file
112
- @url = Neruda::OrgFile.html_file_with_domain @file
121
+ @html_file = nil
122
+ @url = nil
123
+ @project = opts.delete :project
113
124
  @options = opts
125
+ build_html_file_and_url
114
126
  if @file && File.exist?(@file)
115
127
  extract_data
116
128
  else
@@ -166,7 +178,7 @@ module Neruda
166
178
  # @param year [Boolean] wether or not the ~:full~ format must
167
179
  # contain the year
168
180
  # @return [String] the document DateTime string representation
169
- def datestring(dateformat = :full, year = true)
181
+ def datestring(dateformat = :full, year: true)
170
182
  return '' if @date.nil?
171
183
  return R18n.l @date.to_date if dateformat == :short
172
184
  return @date.rfc3339 if dateformat == :rfc3339
@@ -202,6 +214,10 @@ module Neruda
202
214
  # - %l :: the lang of the document
203
215
  # - %L :: the license information, taken from the
204
216
  # {Neruda::Config#settings}
217
+ # - %n :: the Neruda name and version
218
+ # - %N :: the Neruda name and version with a link to the project
219
+ # home on the name
220
+ # - %s :: the subtitle of the document
205
221
  # - %t :: the title of the document
206
222
  # - %u :: the web path to the related published HTML document
207
223
  # - %x :: the raw description (eXcerpt)
@@ -213,8 +229,9 @@ module Neruda
213
229
  # => "Article written by Alice Smith the Wednesday 3rd July"
214
230
  #
215
231
  # @return [String] the given ~string~ after replacement occurs
232
+ # rubocop:disable Metrics/MethodLength
233
+ # rubocop:disable Layout/LineLength
216
234
  def format(string)
217
- license = Neruda::Config.settings['license'] || ''
218
235
  string.gsub('%a', @author)
219
236
  .gsub('%A', author_to_html)
220
237
  .gsub('%d', date_to_html(:short))
@@ -224,12 +241,17 @@ module Neruda
224
241
  .gsub('%k', @keywords.join(', '))
225
242
  .gsub('%K', keywords_to_html)
226
243
  .gsub('%l', @lang)
227
- .gsub('%L', license.gsub(/\s+/, ' ').strip)
244
+ .gsub('%L', (Neruda::Config.settings['license'] || '').gsub(/\s+/, ' ').strip)
245
+ .gsub('%n', "Neruda #{Neruda::VERSION}")
246
+ .gsub('%N', "<a href=\"https://git.umaneti.net/neruda/about/\">Neruda</a> #{Neruda::VERSION}")
247
+ .gsub('%s', @subtitle)
228
248
  .gsub('%t', @title)
229
- .gsub('%u', @html_file)
249
+ .gsub('%u', @html_file || '')
230
250
  .gsub('%x', @excerpt)
231
251
  .gsub('%X', "<p>#{@excerpt}</p>")
232
252
  end
253
+ # rubocop:enable Layout/LineLength
254
+ # rubocop:enable Metrics/MethodLength
233
255
 
234
256
  # Writes the current OrgFile content to the underlying file.
235
257
  #
@@ -246,20 +268,31 @@ module Neruda
246
268
 
247
269
  private
248
270
 
271
+ def build_html_file_and_url
272
+ return if @file.nil?
273
+ @html_file = Neruda::OrgFile.target_for_source(
274
+ @file, @project, with_public_folder: false
275
+ )
276
+ @url = "#{Neruda::Config.settings['domain']}/#{@html_file}"
277
+ end
278
+
249
279
  def init_empty_file
250
280
  @title = @options[:title] || ''
281
+ @subtitle = ''
251
282
  @date = DateTime.now
252
283
  @notime = false
253
284
  @author = @options[:author] || Neruda::Config.settings['author']
254
285
  @keywords = []
255
- @lang = Neruda::Config.settings['lang']
286
+ @lang = @options[:lang] || Neruda::Config.settings['lang']
256
287
  @excerpt = ''
257
- @content = @options[:content] || <<~ORG
288
+ body = @options[:content] || ''
289
+ @content = @options[:raw_content] || <<~ORG
258
290
  #+title: #{@title}
259
291
  #+date: <#{@date.strftime('%Y-%m-%d %a. %H:%M:%S')}>
260
292
  #+author: #{@author}
261
293
  #+language: #{@lang}
262
294
 
295
+ #{body}
263
296
  ORG
264
297
  end
265
298
  end
@@ -3,39 +3,56 @@
3
3
  module Neruda
4
4
  # This module holds class methods for the {Neruda::OrgFile} class.
5
5
  module OrgFileClassMethods
6
- def html_file(file_name)
7
- return nil if file_name.nil?
8
- path = Neruda::OrgFile.target_for_source(file_name)
6
+ def source_for_target(file_name)
7
+ # file_name may be frozen...
8
+ src = file_name.sub(/\.html\z/, '.org')
9
9
  pubfolder = Neruda::Config.settings['public_folder']
10
- path.sub(/^#{pubfolder}\//, '/')
10
+ src.sub!(/^#{pubfolder}\//, '')
11
+ # Look for match in each possible sources. The first found wins.
12
+ Neruda::Config.sources.each do |project|
13
+ if project['target'] == '.'
14
+ origin = File.join(project['path'], src)
15
+ else
16
+ origin = File.join(
17
+ project['path'], src.sub(/^#{project['target']}\//, '')
18
+ )
19
+ end
20
+ return origin if File.exist?(origin)
21
+ end
22
+ nil
11
23
  end
12
24
 
13
- def html_file_with_domain(file_name)
25
+ def target_for_source(file_name, project, with_public_folder: true)
14
26
  return nil if file_name.nil?
15
- Neruda::Config.settings['domain'] + html_file(file_name)
16
- end
17
-
18
- def source_for_target(file_name)
19
27
  # file_name may be frozen...
20
- src = file_name.sub(/\.html$/, '.org')
28
+ target = file_name.sub(/\.org\z/, '.html').sub(/^#{Dir.pwd}\//, '')
29
+ if project.nil?
30
+ subfolder = File.basename(File.dirname(target))
31
+ target = File.basename(target)
32
+ target = "#{subfolder}/#{target}" if subfolder != '.'
33
+ else
34
+ project_relative_path = project['path'].sub(/^#{Dir.pwd}\//, '')
35
+ target.sub!(/^#{project_relative_path}\//, '')
36
+ target = "#{project['target']}/#{target}" if project['target'] != '.'
37
+ end
38
+ return target unless with_public_folder
21
39
  pubfolder = Neruda::Config.settings['public_folder']
22
- src.sub(/^#{pubfolder}\//, 'src/')
40
+ "#{pubfolder}/#{target}"
23
41
  end
24
42
 
25
- def target_for_source(file_name)
26
- # file_name may be frozen...
27
- target = file_name.sub(/\.org$/, '.html')
28
- pubfolder = Neruda::Config.settings['public_folder']
29
- return target.sub(/^src\//, "#{pubfolder}/") if /^src\//.match?(target)
30
- subfolder = File.basename(File.dirname(target))
31
- leaf = File.basename(target)
32
- "#{pubfolder}/#{subfolder}/#{leaf}"
43
+ def project_for_source(file_name)
44
+ # Look for match in each possible sources. The first found wins.
45
+ Neruda::Config.sources.each do |project|
46
+ project_relative_path = project['path'].sub(/^#{Dir.pwd}\//, '')
47
+ return project if file_name.match?(/^#{project_relative_path}\//)
48
+ end
49
+ nil
33
50
  end
34
51
 
35
52
  def slug(title)
36
- title.downcase.gsub(' ', '-')
53
+ title.downcase.tr(' ', '-')
37
54
  .encode('ascii', fallback: ->(k) { translit(k) })
38
- .gsub(/[^\w-]/, '').gsub(/-$/, '')
55
+ .gsub(/[^\w-]/, '').delete_suffix('-')
39
56
  end
40
57
 
41
58
  private
@@ -10,6 +10,7 @@ module Neruda
10
10
  def extract_data
11
11
  @content = IO.read @file
12
12
  @title = extract_title
13
+ @subtitle = extract_subtitle
13
14
  @date = extract_date
14
15
  @author = extract_author
15
16
  @keywords = extract_keywords
@@ -32,7 +33,17 @@ module Neruda
32
33
 
33
34
  def extract_title
34
35
  m = /^#\+title:(.+)$/i.match(@content)
35
- return @file if m.nil?
36
+ if m.nil?
37
+ # Avoid to leak absolute path
38
+ project_relative_path = @file.sub(/^#{Dir.pwd}\//, '')
39
+ return project_relative_path
40
+ end
41
+ m[1].strip
42
+ end
43
+
44
+ def extract_subtitle
45
+ m = /^#\+subtitle:(.+)$/i.match(@content)
46
+ return '' if m.nil?
36
47
  m[1].strip
37
48
  end
38
49
 
@@ -1,22 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'neruda/config'
4
+ require 'neruda/emacs'
4
5
 
5
6
  module Neruda
6
7
  # This module holds HTML formatter methods for the {Neruda::OrgFile}
7
8
  # class.
8
9
  module OrgFileHtmlizer
9
- # Publish the current file or the entire project if
10
- # {Neruda::OrgFile#file @file} is ~nil~.
10
+ # Publish the current file
11
11
  #
12
12
  # @return [Boolean, nil] the underlying ~system~ method return value
13
13
  def publish
14
- if @file.nil?
15
- emacs_args = ['--eval \'(org-publish "website")\'']
16
- else
17
- emacs_args = ['-f org-publish-current-file']
18
- end
19
- call_emacs emacs_args
14
+ Neruda::Emacs.new(
15
+ file_path: @file, verbose: @options[:verbose]
16
+ ).publish
20
17
  end
21
18
 
22
19
  private
@@ -40,7 +37,7 @@ module Neruda
40
37
  #
41
38
  # @return [String] the HTML `time` tag
42
39
  def date_to_html(dateformat = :full)
43
- return '' if @date.nil?
40
+ return '<time></time>' if @date.nil?
44
41
  "<time datetime=\"#{@date.rfc3339}\">#{datestring(dateformat)}</time>"
45
42
  end
46
43
 
@@ -49,30 +46,7 @@ module Neruda
49
46
  #
50
47
  # @return [String] the author HTML `span`
51
48
  def author_to_html
52
- return '' if @author == ''
53
49
  "<span class=\"author\">#{@author}</span>"
54
50
  end
55
-
56
- def emacs_command(arguments = [])
57
- default_emacs = Neruda::Config.settings['emacs']
58
- emacs_cmd = [default_emacs || 'emacs -Q --batch -nw']
59
- emacs_cmd << '--eval \'(setq enable-dir-local-variables nil)\''
60
- unless @options[:verbose]
61
- emacs_cmd << '--eval \'(setq inhibit-message t)\''
62
- end
63
- emacs_cmd << '-l ./org-config.el'
64
- emacs_cmd << "--eval '(find-file \"#{@file}\")'" unless @file.nil?
65
- emacs_cmd.concat(arguments)
66
- emacs_cmd.join(' ')
67
- end
68
-
69
- def call_emacs(arguments = [])
70
- command = emacs_command arguments
71
- if @options[:verbose]
72
- warn command
73
- return system(command)
74
- end
75
- system command, out: '/dev/null', err: '/dev/null'
76
- end
77
51
  end
78
52
  end
@@ -19,11 +19,13 @@ module Neruda # rubocop:disable Style/Documentation
19
19
  private
20
20
 
21
21
  def local_path(requested_path)
22
- routes = Neruda::Config.settings['routes'] || {}
23
- return routes[requested_path] if routes.keys.include? requested_path
22
+ routes = Neruda::Config.settings.dig('preview', 'routes') || {}
23
+ return routes[requested_path] if routes.has_key? requested_path
24
24
  local_path = Neruda::Config.settings['public_folder'] + requested_path
25
25
  if File.directory? local_path
26
- local_path = local_path.delete_suffix('/') + '/index.html'
26
+ local_path = format(
27
+ '%<path>s/index.html', path: local_path.delete_suffix('/')
28
+ )
27
29
  end
28
30
  return local_path if File.exist? local_path
29
31
  raise WEBrick::HTTPStatus::NotFound, 'Not found.'
@@ -31,11 +33,11 @@ module Neruda # rubocop:disable Style/Documentation
31
33
 
32
34
  def parse_body(local_path, local_host)
33
35
  body = IO.read local_path
34
- return body unless local_path.match?(/\.(?:ht|x)ml$/)
36
+ return body unless local_path.match?(/\.(?:ht|x)ml\z/)
35
37
  domain = Neruda::Config.settings['domain']
36
38
  return body if domain == ''
37
- body.gsub(/"file:\/\//, '"' + local_host)
38
- .gsub(/"#{domain}/, '"' + local_host)
39
+ body.gsub(/"file:\/\//, format('"%<host>s', host: local_host))
40
+ .gsub(/"#{domain}/, format('"%<host>s', host: local_host))
39
41
  end
40
42
  end
41
43
 
@@ -43,7 +45,7 @@ module Neruda # rubocop:disable Style/Documentation
43
45
  def start_preview
44
46
  # Inspired by ruby un.rb library, which allows normally to start a
45
47
  # webrick server in one line: ruby -run -e httpd public_html -p 5000
46
- port = Neruda::Config.settings['server_port'] || 5000
48
+ port = Neruda::Config.settings.dig('preview', 'server_port') || 5000
47
49
  s = WEBrick::HTTPServer.new(Port: port)
48
50
  s.mount '/', Neruda::PreviewServlet
49
51
  ['TERM', 'QUIT', 'INT'].each { |sig| trap(sig, proc { s.shutdown }) }
@@ -99,9 +99,10 @@ module Neruda
99
99
  end
100
100
 
101
101
  def insert_new_node_at(elem, content)
102
- if @position == 'before'
102
+ case @position
103
+ when 'before'
103
104
  elem.add_previous_sibling content
104
- elsif @position == 'replace'
105
+ when 'replace'
105
106
  elem.replace content
106
107
  else
107
108
  elem.add_next_sibling content
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'uri'
3
4
  require 'rainbow'
5
+ require 'net/http'
6
+ require 'r18n-core'
4
7
  require 'neruda/config'
5
8
 
6
9
  module Neruda
@@ -23,30 +26,27 @@ module Neruda
23
26
  # configuration
24
27
  PABLO_OPTIONS = {
25
28
  '-a' => { long: 'author' },
29
+ '-d' => { long: 'directory', boolean: true },
30
+ '-f' => { long: 'force', boolean: true },
31
+ '-h' => { long: 'help', boolean: true, meth: :on_tail },
26
32
  '-l' => { long: 'lang', keyword: 'LOCALE' },
33
+ '-p' => { long: 'path' },
27
34
  '-t' => { long: 'title' },
28
- '-p' => { long: 'path', desc: 'Path to the new file' },
29
- '-d' => { long: 'directory', boolean: true,
30
- desc: 'Wrap the new org file in a named folder' },
31
35
  '-v' => { long: 'verbose', boolean: true, meth: :on_tail },
32
- '-h' => { long: 'help', boolean: true, meth: :on_tail,
33
- desc: 'Display help for a command and exit' },
34
- '-V' => { long: 'version', boolean: true, meth: :on_tail,
35
- desc: 'Display Neruda version and exit' }
36
+ '-V' => { long: 'version', boolean: true, meth: :on_tail }
36
37
  }.freeze
37
38
 
38
39
  # @return [Hash] the possible ~pablo~ subcommands and their
39
40
  # configuration
40
41
  PABLO_COMMANDS = {
41
- 'init' => { opts: ['-a', '-l', '-t', '-v', '-h'],
42
- desc: 'Initialize your Neruda instance ' \
43
- '(you just need to do it once).' },
44
- 'preview' => { opts: ['-h'],
45
- desc: 'Start a test webserver to preview ' \
46
- 'your website on http://127.0.0.1:5000' },
47
- 'open' => { opts: ['-a', '-l', '-t', '-d', '-p', '-v', '-h'],
48
- desc: 'Open or create an org file for edition.' },
49
- 'help' => { opts: ['-h'], desc: 'Alias for the -h switch.' },
42
+ 'init' => { opts: ['-a', '-h', '-l', '-t', '-v'] },
43
+ 'config' => { alias: 'init' },
44
+ 'preview' => { opts: ['-h'] },
45
+ 'open' => { opts: ['-a', '-d', '-h', '-l', '-p', '-t', '-v'] },
46
+ 'edit' => { alias: 'open' },
47
+ 'build' => { opts: ['-f', '-h'] },
48
+ 'publish' => { opts: ['-h'] },
49
+ 'help' => { opts: ['-h'] },
50
50
  'basic' => { opts: ['-h', '-V'], label: '<command>' }
51
51
  }.freeze
52
52
 
@@ -66,17 +66,16 @@ module Neruda
66
66
  # @param message [String] the message to display before the throbber
67
67
  # @return [void]
68
68
  def throbber(thread, message)
69
- model = Neruda::Config.settings['throbber'] || 'default'
70
- model = 'default' unless Neruda::Utils::THROBBER_FRAMES.has_key?(model)
71
- frames = Neruda::Utils::THROBBER_FRAMES[model]
72
- current = 0
73
- while thread.alive?
74
- sleep 0.1
75
- print "#{message} #{frames[current % frames.length]}\r"
76
- current += 1
69
+ frames = select_throbber_frames
70
+ begin
71
+ run_and_decorate_thread thread, message, frames
72
+ rescue RuntimeError => e
73
+ throbber_error message
74
+ raise e
75
+ else
76
+ done = Rainbow('done'.ljust(frames[0].length)).green
77
+ puts "#{message} #{done}"
77
78
  end
78
- done = Rainbow('done'.ljust(frames[0].length)).green
79
- puts "#{message} #{done}"
80
79
  end
81
80
 
82
81
  # Returns the short and long options specification for a given
@@ -95,8 +94,8 @@ module Neruda
95
94
  opt = Neruda::Utils::PABLO_OPTIONS[short]
96
95
  long = "--#{opt[:long]}"
97
96
  return [short, long] if opt[:boolean]
98
- key = ' ' + (opt[:keyword] || opt[:long].upcase)
99
- [short + key, long + key]
97
+ key = opt[:keyword] || opt[:long].upcase
98
+ [short + key, format('%<long>s %<key>s', long: long, key: key)]
100
99
  end
101
100
 
102
101
  # Returns the ~pablo~ help summary for a given command.
@@ -108,22 +107,108 @@ module Neruda
108
107
  Neruda::Utils::PABLO_COMMANDS[command][:opts].map do |k|
109
108
  short, long = Neruda::Utils.decorate_option(k)
110
109
  opt = Neruda::Utils::PABLO_OPTIONS[k]
111
- line = ' ' + [short, long].join(', ')
112
- line = line.ljust(34) + " #{opt[:desc]}" if opt.has_key?(:desc)
113
- line + "\n"
114
- end.join
110
+ label = [short, long].join(', ')
111
+ line = [format(' %<opt>s', opt: label).ljust(30)]
112
+ if R18n.t.pablo.options[opt[:long]].translated?
113
+ line << R18n.t.pablo.options[opt[:long]]
114
+ end
115
+ line.join(' ')
116
+ end.join("\n")
115
117
  end
116
118
 
117
119
  # Returns a formatted list of available commands for ~pablo~.
118
120
  #
119
121
  # @return [String]
120
122
  def list_commands
121
- lines = ''
123
+ lines = []
122
124
  Neruda::Utils::PABLO_COMMANDS.each do |cmd, opt|
123
125
  next if cmd == 'basic'
124
- lines += " #{cmd.ljust(10)} #{opt[:desc]}\n"
126
+ line = [' ', cmd.ljust(10)]
127
+ if opt.has_key? :alias
128
+ line << R18n.t.pablo.commands.alias(opt[:alias])
129
+ else
130
+ line << R18n.t.pablo.commands[cmd]
131
+ end
132
+ lines << line.join(' ')
133
+ end
134
+ lines.join("\n")
135
+ end
136
+
137
+ # Returns the real command name for a given command, which may be
138
+ # an alias.
139
+ #
140
+ # @param command [String] the command to resolve
141
+ # @return [String]
142
+ def resolve_possible_alias(command)
143
+ return 'basic' unless Neruda::Utils::PABLO_COMMANDS.include?(command)
144
+ cmd_opt = Neruda::Utils::PABLO_COMMANDS[command]
145
+ return cmd_opt[:alias] if cmd_opt.has_key?(:alias)
146
+ command
147
+ end
148
+
149
+ # Try to discover the current host operating system.
150
+ #
151
+ # @return [String] either apple, windows or linux (default)
152
+ # :nocov:
153
+ def current_os
154
+ if ENV['OS'] == 'Windows_NT' || RUBY_PLATFORM.include?('cygwin')
155
+ return 'windows'
156
+ end
157
+ return 'apple' if RUBY_PLATFORM.include?('darwin')
158
+ 'linux'
159
+ end
160
+ # :nocov:
161
+
162
+ # Download latest org-mode tarball.
163
+ #
164
+ # @return [String] the downloaded org-mode version
165
+ def download_org
166
+ # :nocov:
167
+ return if Neruda::Config.org_last_version.nil?
168
+ # :nocov:
169
+ tarball = "org-#{Neruda::Config.org_last_version}.tar.gz"
170
+ # Remove version number in dest file to allow easy rake file
171
+ # task naming
172
+ dest_file = 'tmp/org.tar.gz'
173
+ return if File.exist?(dest_file)
174
+ uri = URI("https://orgmode.org/#{tarball}")
175
+ # Will crash on purpose if anything goes wrong
176
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
177
+ http.request(Net::HTTP::Get.new(uri)) do |response|
178
+ File.open(dest_file, 'w') do |io|
179
+ response.read_body { |chunk| io.write chunk }
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ private
186
+
187
+ def throbber_error(message)
188
+ warn(
189
+ format(
190
+ "%<message>s %<label>s\n%<explanation>s",
191
+ message: message,
192
+ label: Rainbow(R18n.t.neruda.error.label).bold.red,
193
+ explanation: Rainbow(R18n.t.neruda.error.explanation).bold
194
+ )
195
+ )
196
+ end
197
+
198
+ def select_throbber_frames
199
+ model = Neruda::Config.settings['throbber'] || 'default'
200
+ model = 'default' unless Neruda::Utils::THROBBER_FRAMES.has_key?(model)
201
+ Neruda::Utils::THROBBER_FRAMES[model]
202
+ end
203
+
204
+ def run_and_decorate_thread(thread, message, frames)
205
+ thread.abort_on_exception = true
206
+ current = 0
207
+ while thread.alive?
208
+ sleep 0.1
209
+ print "#{message} #{frames[current % frames.length]}\r"
210
+ current += 1
125
211
  end
126
- lines
127
212
  end
128
213
  end
129
214
  end