Module: Howdoc

Defined in:
lib/howdoc.rb,
lib/howdoc/step.rb,
lib/howdoc/marker.rb,
lib/howdoc/edition.rb,
lib/howdoc/version.rb,
lib/howdoc/writers.rb,
lib/howdoc/document.rb,
lib/howdoc/minitest.rb,
lib/howdoc/narrator.rb,
lib/howdoc/recorder.rb,
lib/howdoc/registry.rb,
lib/howdoc/templates.rb,
lib/howdoc/navigation.rb,
lib/howdoc/screenshot.rb,
lib/howdoc/configuration.rb,
lib/howdoc/capybara_actions.rb

Overview

Generates end-user documentation from Capybara system tests.

A test that already drives the browser knows every step a person would take. Howdoc listens to those steps, narrates them, photographs the result and writes an illustrated guide. Because the guide comes out of a test that has to pass, it cannot quietly drift away from the application it describes.

Defined Under Namespace

Modules: CapybaraActions, Marker, MinitestIntegration, Narrator, Navigation, Recorder, Registry, Screenshot, Templates, Writers Classes: Configuration, Document, Edition, Step

Constant Summary collapse

LOCALES_ROOT =
File.expand_path('../config/locales', __dir__)
VERSION =
'0.5.0'

Class Method Summary collapse

Class Method Details

.blank_title?(title) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
93
94
# File 'lib/howdoc.rb', line 90

def blank_title?(title)
  return title.values.all? { |value| blank_title?(value) } if title.is_a?(Hash)

  title.to_s.strip.empty?
end

.captureObject



115
116
117
# File 'lib/howdoc.rb', line 115

def capture(...)
  Recorder.capture(...)
end

.cleanObject



136
137
138
# File 'lib/howdoc.rb', line 136

def clean
  Registry.clean
end

.configObject



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

def config
  @config ||= Configuration.new
end

.configure {|config| ... } ⇒ Object

Yields:



34
35
36
37
38
# File 'lib/howdoc.rb', line 34

def configure
  yield(config)
  install_locales
  config
end

.currentObject



107
108
109
# File 'lib/howdoc.rb', line 107

def current
  Recorder.current
end

.document_locales(locale, locales) ⇒ Object

Which languages a guide is written in: what the caller asked for, else what the application publishes, else the language the suite is running in, which is all a single-language application ever needs.



83
84
85
86
87
88
# File 'lib/howdoc.rb', line 83

def document_locales(locale, locales)
  chosen = locales || locale || config.locales
  chosen = I18n.locale if chosen.nil? || Array(chosen).empty?

  Array(chosen).map(&:to_sym)
end

.enabled?Boolean

Returns:

  • (Boolean)


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

def enabled?
  config.enabled?
end

.extract_options!Object



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

def extract_options!(...)
  Recorder.extract_options!(...)
end

.finalizeObject

Assembles the index from the manifests. Run once, after the whole suite.



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

def finalize
  return [] unless enabled?

  Registry.write_indexes
ensure
  warn_about_missing_translations
end

.finishObject

Ends the guide and writes it out. Called even when the test failed, so a broken step leaves visible evidence instead of no page at all.



98
99
100
101
102
103
104
105
# File 'lib/howdoc.rb', line 98

def finish
  document = Recorder.current
  Recorder.current = nil
  return nil if document.nil? || document.steps.empty?

  Writers.write(document)
  document
end

.install_localesObject

Adds the gem's own English and then any translations the application registered, so an application only has to translate what it wants to say differently.



53
54
55
56
57
58
59
60
61
# File 'lib/howdoc.rb', line 53

def install_locales
  globs = [File.join(LOCALES_ROOT, '*.yml')] + config.locale_paths
  added = globs.flat_map { |glob| Dir.glob(glob) } - I18n.load_path

  return if added.empty?

  I18n.load_path.concat(added)
  I18n.backend.reload! if I18n.backend.respond_to?(:reload!)
end

.recordObject



111
112
113
# File 'lib/howdoc.rb', line 111

def record(...)
  Recorder.record(...)
end

.record_and_captureObject



119
120
121
# File 'lib/howdoc.rb', line 119

def record_and_capture(...)
  Recorder.record_and_capture(...)
end

.reset!Object



40
41
42
43
44
# File 'lib/howdoc.rb', line 40

def reset!
  @config = nil
  Recorder.current = nil
  Narrator.reset_missing_keys
end

.start(id: nil, title: nil, locale: nil, locales: nil, permalink: nil, intro: nil) ⇒ Object

Begins a guide. Everything recorded until #finish belongs to it.

A test runs in one language; the guide it records is written in every language the application publishes, which is config.locales unless this call names them. Pass locale: for the rare guide that belongs to one language only -- a page describing something only that language's users ever see.



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

def start(id: nil, title: nil, locale: nil, locales: nil, permalink: nil, intro: nil)
  return nil unless enabled?
  return nil if blank_title?(title)

  Recorder.current = Document.new(
    id:, title:, permalink:, intro:,
    locales: document_locales(locale, locales)
  )
end

.warn_about_missing_translationsObject



140
141
142
143
144
145
146
# File 'lib/howdoc.rb', line 140

def warn_about_missing_translations
  keys = Narrator.missing_keys
  return if keys.empty?

  warn "\nHowdoc: #{keys.size} untranslated step(s), the guides are missing those instructions:"
  keys.sort.each { |key| warn "  #{key}" }
end