Class: JsDuck::Options

Inherits:
Object
  • Object
show all
Defined in:
lib/jsduck/options.rb

Overview

Keeps command line options

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeOptions

Returns a new instance of Options.



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
# File 'lib/jsduck/options.rb', line 48

def initialize
  @input_files = []

  @output_dir = nil
  @ignore_global = false
  @external_classes = [
    # JavaScript builtins
    "Object",
    "String",
    "Number",
    "Boolean",
    "RegExp",
    "Function",
    "Array",
    "Arguments",
    "Date",
    "Error",
    # DOM
    "HTMLElement",
    "XMLElement",
    "NodeList",
    "TextNode",
    "CSSStyleSheet",
    "CSSStyleRule",
    "Event",
    # Special anything-goes type
    "Mixed",
  ]
  @meta_tag_paths = []

  @version = "3.10.1"

  # Customizing output
  @title = "Sencha Docs - Ext JS"
  @header = "<strong>Sencha Docs</strong> Ext JS"
  @footer = "Generated with <a href='https://github.com/senchalabs/jsduck'>JSDuck</a> #{@version}."
  @head_html = ""
  @body_html = ""
  @welcome = nil
  @guides = nil
  @videos = nil
  @examples = nil
  @stats = false
  @categories_path = nil
  @source = true
  @pretty_json = false
  @images = []
  @link_tpl = '<a href="#!/api/%c%-%m" rel="%c%-%m" class="docClass">%a</a>'
  # Note that we wrap image template inside <p> because {@img} often
  # appears inline within text, but that just looks ugly in HTML
  @img_tpl = '<p><img src="%u" alt="%a"></p>'
  @export = nil
  @seo = false
  @eg_iframe = nil
  @examples_base_url = "extjs-build/examples/"
  @tests = false

  # Debugging
  # Turn multiprocessing off by default in Windows
  @processes = OS::windows? ? 0 : nil
  @root_dir = File.dirname(File.dirname(File.dirname(__FILE__)))
  @template_dir = @root_dir + "/template-min"
  @template_links = false
  @extjs_path = "extjs/ext-all.js"
  @local_storage_db = "docs"
  @touch_examples_ui = false
  @ext_namespaces = ["Ext"]

  # enable all warnings except :link_auto
  Logger.instance.set_warning(:all, true)
  Logger.instance.set_warning(:link_auto, false)
end

Instance Attribute Details

#body_htmlObject

Returns the value of attribute body_html.



21
22
23
# File 'lib/jsduck/options.rb', line 21

def body_html
  @body_html
end

#categories_pathObject

Returns the value of attribute categories_path.



27
28
29
# File 'lib/jsduck/options.rb', line 27

def categories_path
  @categories_path
end

#eg_iframeObject

Returns the value of attribute eg_iframe.



35
36
37
# File 'lib/jsduck/options.rb', line 35

def eg_iframe
  @eg_iframe
end

#examplesObject

Returns the value of attribute examples.



25
26
27
# File 'lib/jsduck/options.rb', line 25

def examples
  @examples
end

#examples_base_urlObject

Returns the value of attribute examples_base_url.



36
37
38
# File 'lib/jsduck/options.rb', line 36

def examples_base_url
  @examples_base_url
end

#exportObject

Returns the value of attribute export.



33
34
35
# File 'lib/jsduck/options.rb', line 33

def export
  @export
end

#ext_namespacesObject

Returns the value of attribute ext_namespaces.



46
47
48
# File 'lib/jsduck/options.rb', line 46

def ext_namespaces
  @ext_namespaces
end

#external_classesObject

Returns the value of attribute external_classes.



14
15
16
# File 'lib/jsduck/options.rb', line 14

def external_classes
  @external_classes
end

#extjs_pathObject

Returns the value of attribute extjs_path.



43
44
45
# File 'lib/jsduck/options.rb', line 43

def extjs_path
  @extjs_path
end

Returns the value of attribute footer.



19
20
21
# File 'lib/jsduck/options.rb', line 19

def footer
  @footer
end

#guidesObject

Returns the value of attribute guides.



23
24
25
# File 'lib/jsduck/options.rb', line 23

def guides
  @guides
end

#head_htmlObject

Returns the value of attribute head_html.



20
21
22
# File 'lib/jsduck/options.rb', line 20

def head_html
  @head_html
end

#headerObject

Returns the value of attribute header.



18
19
20
# File 'lib/jsduck/options.rb', line 18

def header
  @header
end

#ignore_globalObject

Returns the value of attribute ignore_global.



13
14
15
# File 'lib/jsduck/options.rb', line 13

def ignore_global
  @ignore_global
end

#imagesObject

Returns the value of attribute images.



30
31
32
# File 'lib/jsduck/options.rb', line 30

def images
  @images
end

#img_tplObject

Returns the value of attribute img_tpl.



32
33
34
# File 'lib/jsduck/options.rb', line 32

def img_tpl
  @img_tpl
end

#input_filesObject

Returns the value of attribute input_files.



10
11
12
# File 'lib/jsduck/options.rb', line 10

def input_files
  @input_files
end

Returns the value of attribute link_tpl.



31
32
33
# File 'lib/jsduck/options.rb', line 31

def link_tpl
  @link_tpl
end

#local_storage_dbObject

Returns the value of attribute local_storage_db.



44
45
46
# File 'lib/jsduck/options.rb', line 44

def local_storage_db
  @local_storage_db
end

#output_dirObject

Returns the value of attribute output_dir.



12
13
14
# File 'lib/jsduck/options.rb', line 12

def output_dir
  @output_dir
end

#pretty_jsonObject

Returns the value of attribute pretty_json.



29
30
31
# File 'lib/jsduck/options.rb', line 29

def pretty_json
  @pretty_json
end

#processesObject

Debugging



40
41
42
# File 'lib/jsduck/options.rb', line 40

def processes
  @processes
end

#seoObject

Returns the value of attribute seo.



34
35
36
# File 'lib/jsduck/options.rb', line 34

def seo
  @seo
end

#sourceObject

Returns the value of attribute source.



28
29
30
# File 'lib/jsduck/options.rb', line 28

def source
  @source
end

#statsObject

Returns the value of attribute stats.



26
27
28
# File 'lib/jsduck/options.rb', line 26

def stats
  @stats
end

#template_dirObject

Returns the value of attribute template_dir.



41
42
43
# File 'lib/jsduck/options.rb', line 41

def template_dir
  @template_dir
end

Returns the value of attribute template_links.



42
43
44
# File 'lib/jsduck/options.rb', line 42

def template_links
  @template_links
end

#testsObject

Returns the value of attribute tests.



37
38
39
# File 'lib/jsduck/options.rb', line 37

def tests
  @tests
end

#titleObject

Customizing output



17
18
19
# File 'lib/jsduck/options.rb', line 17

def title
  @title
end

#touch_examples_uiObject

Returns the value of attribute touch_examples_ui.



45
46
47
# File 'lib/jsduck/options.rb', line 45

def touch_examples_ui
  @touch_examples_ui
end

#videosObject

Returns the value of attribute videos.



24
25
26
# File 'lib/jsduck/options.rb', line 24

def videos
  @videos
end

#welcomeObject

Returns the value of attribute welcome.



22
23
24
# File 'lib/jsduck/options.rb', line 22

def welcome
  @welcome
end

Instance Method Details

#[](key) ⇒ Object

Make options object behave like hash. This allows us to substitute it with hash in unit tests.



123
124
125
# File 'lib/jsduck/options.rb', line 123

def [](key)
  send(key)
end

#canonical(path) ⇒ Object

Converts relative path to full path

Especially important for running on Windows where C:foobar pathnames are converted to C:/foo/bar which ruby can work on more easily.



485
486
487
# File 'lib/jsduck/options.rb', line 485

def canonical(path)
  File.expand_path(path, @working_dir)
end

#create_option_parserObject



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
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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
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
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/jsduck/options.rb', line 138

def create_option_parser
  optparser = OptionParser.new do | opts |
    opts.banner = "Usage: jsduck [options] files/dirs...\n\n"

    opts.on('-o', '--output=PATH',
      "Directory to output all this amazing documentation.",
      "This option MUST be specified (unless --stdout).",
      "Use dash '-' to write docs to STDOUT (only export).", " ") do |path|
      @output_dir = path == "-" ? :stdout : canonical(path)
    end

    opts.on('--ignore-global', "Turns off the creation of global class.", " ") do
      @ignore_global = true
    end

    opts.on('--external=Foo,Bar,Baz', Array,
      "Declares list of external classes.  These classes",
      "will then not generate warnings when used in type",
      "definitions or inherited from.", " ") do |classes|
      @external_classes += classes
    end

    opts.on('--builtin-classes',
      "Includes docs for JavaScript builtin classes.", " ") do
      read_filenames(@root_dir + "/js-classes")
    end

    opts.on('--meta-tags=PATH',
      "Path to Ruby file or directory with custom",
      "meta-tag implementations.", " ") do |path|
      @meta_tag_paths << canonical(path)
    end

    opts.on('--encoding=NAME', "Input encoding (defaults to UTF-8).", " ") do |encoding|
      JsDuck::IO.encoding = encoding
    end

    opts.on('-v', '--verbose', "This will fill up your console.", " ") do
      Logger.instance.verbose = true
    end

    opts.separator "Customizing output:"
    opts.separator ""

    opts.on('--title=TEXT',
      "Custom title text for the documentation.",
      "Defaults to 'Sencha Docs - Ext JS'", " ") do |text|
      @title = text
      @header = text.sub(/^(.*?) +- +/, "<strong>\\1 </strong>")
    end

    opts.on('--footer=TEXT',
      "Custom footer text for the documentation.",
      "Defaults to: 'Generated with JSDuck {VERSION}.'", " ") do |text|
      @footer = text.gsub(/\{VERSION\}/, @version)
    end

    opts.on('--head-html=HTML', "HTML to append to the <head> section of index.html.", " ") do |html|
      @head_html += html
    end

    opts.on('--body-html=HTML', "HTML to append to the <body> section index.html.", " ") do |html|
      @body_html += html
    end

    opts.on('--welcome=PATH',
      "Path to HTML file with content for welcome page.", " ") do |path|
      @welcome = canonical(path)
    end

    opts.on('--guides=PATH',
      "Path to JSON file describing the guides. The file",
      "should be in a dir containing the actual guides.",
      "A guide is a dir containing README.md, icon.png,",
      "and other images referenced by the README.md file.", " ") do |path|
      @guides = canonical(path)
    end

    opts.on('--videos=PATH',
      "Path to JSON file describing the videos.", " ") do |path|
      @videos = canonical(path)
    end

    opts.on('--examples=PATH',
      "Path JSON file describing the examples.", " ") do |path|
      @examples = canonical(path)
    end

    opts.on('--categories=PATH',
      "Path to JSON file which defines categories for classes.", " ") do |path|
      @categories_path = canonical(path)
    end

    opts.on('--no-source',
      "Turns off the output of source files.", " ") do
      @source = false
    end

    opts.on('--pretty-json', "Turn on pretty-printing of JSON.", " ") do
      @pretty_json = true
    end

    opts.on('--images=PATH',
      "Search path for including images referenced by",
      "{@img} tag. Several paths can be specified by",
      "using the option multiple times.", " ") do |path|
      @images << canonical(path)
    end

    opts.on('--link=TPL',
      "HTML template for replacing {@link}.",
      "Possible placeholders:",
      "%c - full class name (e.g. 'Ext.Panel')",
      "%m - class member name prefixed with member type",
      "     (e.g. 'method-urlEncode')",
      "%# - inserts '#' if member name present",
      "%- - inserts '-' if member name present",
      "%a - anchor text for link",
      "Default is: '<a href=\"#!/api/%c%-%m\" rel=\"%c%-%m\" class=\"docClass\">%a</a>'", " ") do |tpl|
      @link_tpl = tpl
    end

    opts.on('--img=TPL',
      "HTML template for replacing {@img}.",
      "Possible placeholders:",
      "%u - URL from @img tag (e.g. 'some/path.png')",
      "%a - alt text for image",
      "Default is: '<p><img src=\"%u\" alt=\"%a\"></p>'", " ") do |tpl|
      @img_tpl = tpl
    end

    opts.on('--export=TYPE',
      "Exports docs in JSON.  TYPE is one of:",
      "* full     - full class docs.",
      "* api      - only class- and member names.",
      "* examples - extracts inline examples from classes.", " ") do |format|
      @export = format.to_sym
    end

    opts.on('--seo', "Creates index.php that handles search engine traffic.", " ") do
      @seo = true
    end

    opts.on('--eg-iframe=PATH',
      "An HTML file to use inside an iframe",
      "to display inline examples.", " ") do |path|
      @eg_iframe = canonical(path)
    end

    opts.on('--examples-base-url=URL',
      "Base URL for examples with relative URL-s.", " ") do |path|
      @examples_base_url = path
    end

    opts.on('--tests', "Creates page for testing inline examples.", " ") do
      @tests = true
    end

    opts.on('--stats',
      "Creates page with all kinds of statistics. Experimental!", " ") do
      @stats = true
    end

    opts.separator "Debugging:"
    opts.separator ""

    opts.on('--warnings=+A,-B,+C', Array,
      "Turns warnings selectively on/off.",
      " ",
      " +all - to turn on all warnings",
      " ",
      "By default these warnings are turned +on/-off:",
      " ",
      *Logger.instance.doc_warnings) do |warnings|
      warnings.each do |op|
        if op =~ /^([-+]?)(.*)$/
          enable = !($1 == "-")
          name = $2.to_sym
          Logger.instance.set_warning(name, enable)
        end
      end
    end

    # For debugging it's often useful to set --processes=0 to get deterministic results.
    opts.on('-p', '--processes=COUNT',
      "The number of parallel processes to use.",
      OS::windows? ? "Defaults to off in Windows." : "Defaults to the number of processors/cores.",
      "Set to 0 to disable parallel processing completely.", " ") do |count|
      @processes = count.to_i
    end

    opts.on('--template=PATH',
      "Directory containing doc-browser UI template.", " ") do |path|
      @template_dir = canonical(path)
    end

    opts.on('--template-links',
      "Instead of copying template files, create symbolic",
      "links.  Useful for template files development.",
      "Only works on platforms supporting symbolic links.", " ") do
      @template_links = true
    end

    opts.on('--extjs-path=PATH',
      "Path for main ExtJS JavaScript file.  Useful for specifying",
      "something different than extjs/ext.js", " ") do |path|
      @extjs_path = path # NB! must be relative path
    end

    opts.on('--local-storage-db=NAME',
      "Prefix for LocalStorage database names.",
      "Defaults to 'docs'.", " ") do |name|
      @local_storage_db = name
    end

    opts.on('--touch-examples-ui',
      "Use phone/tablet UI for examples.", " ") do
      @touch_examples_ui = true
    end

    opts.on('--ext-namespaces=Ext,Foo', Array,
      "Namespace(s) of ExtJS. Defaults to 'Ext'.", " ") do |ns|
      @ext_namespaces = ns
    end

    opts.on('--config=PATH',
      "Loads config options from JSON file.", " ") do |path|
      path = canonical(path)
      if File.exists?(path)
        config = read_json_config(path)
      else
        puts "Oh noes!  The config file #{path} doesn't exist."
        exit(1)
      end
      # treat paths inside JSON config relative to the location of
      # config file.  When done, switch back to current working dir.
      @working_dir = File.dirname(path)
      optparser.parse!(config).each {|fname| read_filenames(canonical(fname)) }
      @working_dir = nil
    end

    opts.on('-h', '--help[=full]',
      "Short help or --help=full for all available options.", " ") do |v|
      if v == 'full'
        puts opts
      else
        puts opts.banner
        puts "For example:"
        puts
        puts "    # Documentation for builtin JavaScript classes like Array and String"
        puts "    jsduck --output output/dir  --builtin-classes"
        puts
        puts "    # Documentation for your own JavaScript"
        puts "    jsduck --output output/dir  input-file.js some/input/dir"
        puts
        puts "The main options:"
        puts

        show_help = false
        main_opts = [
          /--output/,
          /--builtin-classes/,
          /--encoding/,
          /--verbose/,
          /--help/,
          /--version/,
        ]
        opts.summarize([], opts.summary_width) do |helpline|
          if main_opts.any? {|re| helpline =~ re }
            puts helpline
            show_help = true
          elsif helpline =~ /^\s*$/ && show_help == true
            puts helpline
            show_help = false
          elsif show_help == true
            puts helpline
          end
        end
      end
      exit
    end

    opts.on('--version', "Prints JSDuck version", " ") do
      puts "JSDuck " + @version
      exit
    end
  end

  return optparser
end

#extract_jsb_files(jsb_file) ⇒ Object

Extracts files of first build in jsb file



468
469
470
471
472
473
474
475
476
477
478
# File 'lib/jsduck/options.rb', line 468

def extract_jsb_files(jsb_file)
  json = JsonDuck::read(jsb_file)
  basedir = File.dirname(jsb_file)

  return json["builds"][0]["packages"].map do |package_id|
    package = json["packages"].find {|p| p["id"] == package_id }
    (package ? package["files"] : []).map do |file|
      File.expand_path(basedir + "/" + file["path"] + file["name"])
    end
  end.flatten
end

#parse!(argv) ⇒ Object



127
128
129
130
131
132
133
134
135
136
# File 'lib/jsduck/options.rb', line 127

def parse!(argv)
  create_option_parser.parse!(argv).each do |fname|
    read_filenames(canonical(fname))
  end
  validate

  reg = MetaTagRegistry.new
  reg.load([:builtins] + @meta_tag_paths)
  MetaTagRegistry.instance = reg
end

#read_filenames(fname) ⇒ Object

scans directory for .js files or simply adds file to input files list



453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'lib/jsduck/options.rb', line 453

def read_filenames(fname)
  if File.exists?(fname)
    if File.directory?(fname)
      Dir[fname+"/**/*.{js,css,scss}"].each {|f| @input_files << f }
    elsif fname =~ /\.jsb3$/
      extract_jsb_files(fname).each {|fn| read_filenames(fn) }
    else
      @input_files << fname
    end
  else
    Logger.instance.warn(nil, "File #{fname} not found")
  end
end

#read_json_config(fname) ⇒ Object

Reads JSON configuration from file and returns an array of config options that can be feeded into optparser.



431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/jsduck/options.rb', line 431

def read_json_config(fname)
  config = []
  json = JsonDuck.read(fname)
  json.each_pair do |key, value|
    if key == "--"
      # filenames
      config += Array(value).map(&:to_s)
    elsif value == true
      # simple switch
      config += [key.to_s]
    else
      # An option with value or with multiple values.
      # In the latter case, add the option multiple times.
      Array(value).each do |v|
        config += [key.to_s, v.to_s]
      end
    end
  end
  config
end

#validateObject

Runs checks on the options



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
# File 'lib/jsduck/options.rb', line 490

def validate
  if @input_files.length == 0 && !@welcome && !@guides && !@videos && !@examples
    puts "You should specify some input files, otherwise there's nothing I can do :("
    exit(1)
  elsif @output_dir == :stdout && !@export
    puts "Output to STDOUT only works when using --export option."
    exit(1)
  elsif ![nil, :full, :api, :examples].include?(@export)
    puts "Unknown export format: #{@export}"
    exit(1)
  elsif @output_dir != :stdout
    if !@output_dir
      puts "You should also specify an output directory, where I could write all this amazing documentation."
      exit(1)
    elsif File.exists?(@output_dir) && !File.directory?(@output_dir)
      puts "Oh noes!  The output directory is not really a directory at all :("
      exit(1)
    elsif !File.exists?(File.dirname(@output_dir))
      puts "Oh noes!  The parent directory for #{@output_dir} doesn't exist."
      exit(1)
    elsif !@export && !File.exists?(@template_dir + "/extjs")
      puts "Oh noes!  The template directory does not contain extjs/ directory :("
      puts "Please copy ExtJS over to template/extjs or create symlink."
      puts "For example:"
      puts "    $ cp -r /path/to/ext-4.0.0 " + @template_dir + "/extjs"
      exit(1)
    elsif !@export && !File.exists?(@template_dir + "/resources/css")
      puts "Oh noes!  CSS files for custom ExtJS theme missing :("
      puts "Please compile SASS files in template/resources/sass with compass."
      puts "For example:"
      puts "    $ compass compile " + @template_dir + "/resources/sass"
      exit(1)
    end
  end
end