rspec-documentation 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/Gemfile.lock +3 -3
  4. data/Makefile +9 -0
  5. data/README.md +17 -21
  6. data/exe/rspec-documentation +5 -1
  7. data/lib/rspec/documentation/version.rb +1 -1
  8. data/lib/rspec/documentation.rb +1 -51
  9. data/lib/rspec_documentation/configuration.rb +17 -4
  10. data/lib/rspec_documentation/document.rb +17 -5
  11. data/lib/rspec_documentation/documentation.rb +85 -0
  12. data/lib/rspec_documentation/formatters/ansi.rb +44 -0
  13. data/lib/rspec_documentation/formatters/html.rb +31 -0
  14. data/lib/rspec_documentation/formatters/json.rb +32 -0
  15. data/lib/rspec_documentation/formatters/ruby.rb +31 -0
  16. data/lib/rspec_documentation/formatters/yaml.rb +36 -0
  17. data/lib/rspec_documentation/formatters.rb +20 -0
  18. data/lib/rspec_documentation/html_element.rb +21 -18
  19. data/lib/rspec_documentation/javascript_bundle.rb +17 -0
  20. data/lib/rspec_documentation/page_collection.rb +24 -9
  21. data/lib/rspec_documentation/page_tree.rb +16 -8
  22. data/lib/rspec_documentation/page_tree_element.rb +31 -9
  23. data/lib/rspec_documentation/parsed_document.rb +5 -3
  24. data/lib/rspec_documentation/project_initialization.rb +52 -0
  25. data/lib/rspec_documentation/rspec/failure.rb +20 -5
  26. data/lib/rspec_documentation/rspec.rb +0 -2
  27. data/lib/rspec_documentation/spec.rb +58 -12
  28. data/lib/rspec_documentation/stylesheet_bundle.rb +17 -0
  29. data/lib/rspec_documentation/summary.rb +87 -0
  30. data/lib/rspec_documentation/util.rb +12 -0
  31. data/lib/rspec_documentation.rb +16 -3
  32. data/lib/templates/000-Introduction.md.erb +35 -0
  33. data/lib/templates/010-Usage.md.erb +3 -0
  34. data/lib/templates/500-License.md.erb +3 -0
  35. data/lib/templates/bootstrap.js.erb +7 -0
  36. data/lib/templates/footer.html.erb +5 -0
  37. data/lib/templates/header.html.erb +16 -3
  38. data/lib/templates/layout.css.erb +381 -2
  39. data/lib/templates/layout.html.erb +13 -82
  40. data/lib/templates/layout.js.erb +67 -0
  41. data/lib/templates/modal_spec.html.erb +51 -0
  42. data/lib/templates/moon.svg.erb +1 -0
  43. data/lib/templates/script_tags.html.erb +1 -0
  44. data/lib/templates/stylesheet_links.html.erb +1 -0
  45. data/lib/templates/sun.svg.erb +1 -0
  46. data/lib/templates/tabbed_spec.html.erb +12 -49
  47. data/lib/templates/themes/bootstrap.min.css +11 -0
  48. data/lib/templates/themes/cerulean.css +5 -6
  49. data/lib/templates/themes/cosmo.css +5 -6
  50. data/lib/templates/themes/cyborg.css +5 -6
  51. data/lib/templates/themes/darkly.css +5 -6
  52. data/lib/templates/themes/flatly.css +5 -6
  53. data/lib/templates/themes/journal.css +5 -6
  54. data/lib/templates/themes/litera.css +5 -6
  55. data/lib/templates/themes/lumen.css +5 -6
  56. data/lib/templates/themes/lux.css +5 -6
  57. data/lib/templates/themes/materia.css +5 -6
  58. data/lib/templates/themes/minty.css +5 -6
  59. data/lib/templates/themes/morph.css +5 -6
  60. data/lib/templates/themes/pulse.css +5 -6
  61. data/lib/templates/themes/quartz.css +5 -6
  62. data/lib/templates/themes/sandstone.css +5 -6
  63. data/lib/templates/themes/simplex.css +5 -6
  64. data/lib/templates/themes/sketchy.css +5 -6
  65. data/lib/templates/themes/slate.css +5 -6
  66. data/lib/templates/themes/solar.css +5 -6
  67. data/lib/templates/themes/spacelab.css +5 -6
  68. data/lib/templates/themes/superhero.css +5 -6
  69. data/lib/templates/themes/united.css +5 -6
  70. data/lib/templates/themes/vapor.css +5 -6
  71. data/lib/templates/themes/yeti.css +5 -6
  72. data/lib/templates/themes/zephyr.css +5 -6
  73. data/rspec-documentation/pages/000-Introduction/000-Quickstart.md +17 -0
  74. data/rspec-documentation/pages/000-Introduction.md +14 -30
  75. data/rspec-documentation/pages/010-File System/000-Ordering.md +1 -1
  76. data/rspec-documentation/pages/010-File System/010-Documentation Bundle.md +9 -0
  77. data/rspec-documentation/pages/010-File System.md +1 -1
  78. data/rspec-documentation/pages/020-Running Tests.md +41 -0
  79. data/rspec-documentation/pages/030-Examples/010-Basic.md +51 -0
  80. data/rspec-documentation/pages/030-Examples/020-HTML.md +45 -0
  81. data/rspec-documentation/pages/030-Examples/030-ANSI.md +33 -0
  82. data/rspec-documentation/pages/030-Examples/040-JSON.md +39 -0
  83. data/rspec-documentation/pages/030-Examples/050-YAML.md +40 -0
  84. data/rspec-documentation/pages/030-Examples.md +7 -0
  85. data/rspec-documentation/pages/040-Spec Helper.md +11 -0
  86. data/rspec-documentation/pages/050-Linking.md +20 -0
  87. data/rspec-documentation/pages/060-Configuration/010-Context.md +26 -0
  88. data/rspec-documentation/pages/060-Configuration/020-Build Paths.md +33 -0
  89. data/rspec-documentation/pages/060-Configuration/030-Attribution.md +23 -0
  90. data/rspec-documentation/pages/060-Configuration.md +13 -0
  91. data/rspec-documentation/pages/070-Publishing.md +13 -0
  92. data/rspec-documentation/pages/500-License.md +11 -0
  93. data/rspec-documentation/spec_helper.rb +8 -0
  94. data/rspec-documentation.gemspec +2 -1
  95. metadata +46 -12
  96. data/lib/rspec_documentation/ansi_html.rb +0 -28
  97. data/lib/rspec_documentation/context.rb +0 -44
  98. data/lib/rspec_documentation/rspec/example_group.rb +0 -26
  99. data/lib/rspec_documentation/rspec/reporter.rb +0 -45
  100. data/rspec-documentation/pages/010-File System/010-Standalone Directories.md +0 -17
  101. data/rspec-documentation/pages/010-File System/020-Standalone Directory/Example Page.md +0 -3
  102. data/rspec-documentation/pages/020-Running Specs.md +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1de5016a8e2e1a370ac923d9501c654c56e87e1f236f2f260ea634a8a28167b4
4
- data.tar.gz: d75c74d43b80b502daa00778c3d4e8ede22514c2f500d67ee6dc31cb994772e3
3
+ metadata.gz: a33d3b35a6feaea6cdb730424eabca522ee5592f7e944b9c751713b12c3c35d5
4
+ data.tar.gz: 90be4151f65ecb8e0e4a74f70c85cdae67df5d78ed31acd0cc2fa2c7da72a2f2
5
5
  SHA512:
6
- metadata.gz: 1bc358ecfcda3670c648dac2f11698facb57c2dc147826a87a26b24af07a1517fda6cd43431be25facb996280e7de50848630f0f8aab9ead11743ac1ec76e77e
7
- data.tar.gz: a622ad2f53e2c743431678ed97e9a36a037c86f5b4b15c67c3eff439158ff0af026878be1f55a1aa5d4ee45b1a672a57db66c28912de012471d5bcd7aeedb6b1
6
+ metadata.gz: f357c76176c0f5cc9a2061a51dfa3fceb59f05d75fe5173ed211dee64e1e4c07bb6309448757f1172f7b79f4b80f0c55c8fca99ca430eb17bb2b1766390ca1de
7
+ data.tar.gz: b5598da557e010fb880dd001297d5d7796f46b7f2f2e7bf39847eec33073402f852f14f8113474c3ba00f950ee5b53b20af2d259b584a0bd5fe23cac707591bb
data/.rubocop.yml CHANGED
@@ -6,3 +6,4 @@ AllCops:
6
6
  NewCops: enable
7
7
  Exclude:
8
8
  - 'spec/fixtures/**/*'
9
+ - 'lib/rspec_documentation/page_tree.rb' # Rubocop bug, fixed in main
data/Gemfile.lock CHANGED
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-documentation (0.0.2)
4
+ rspec-documentation (0.0.4)
5
5
  htmlbeautifier (~> 1.4)
6
6
  kramdown (~> 2.4)
7
7
  kramdown-parser-gfm (~> 1.1)
8
- paintbrush (~> 0.1.1)
8
+ paintbrush (~> 0.1.3)
9
9
  redcarpet (~> 3.6)
10
10
  rouge (~> 4.1)
11
11
  rspec (~> 3.12)
@@ -26,7 +26,7 @@ GEM
26
26
  kramdown-parser-gfm (1.1.0)
27
27
  kramdown (~> 2.0)
28
28
  paint (2.3.0)
29
- paintbrush (0.1.1)
29
+ paintbrush (0.1.3)
30
30
  parallel (1.23.0)
31
31
  parser (3.2.2.1)
32
32
  ast (~> 2.4.1)
data/Makefile CHANGED
@@ -1,5 +1,14 @@
1
+ project=rspec-documentation
2
+
1
3
  .PHONY: test
2
4
  test:
3
5
  bundle exec rspec
4
6
  bundle exec rubocop
5
7
  bundle exec strong_versions
8
+ exe/rspec-documentation
9
+
10
+ .PHONY: publish
11
+ publish:
12
+ @RSPEC_DOCUMENTATION_URL_ROOT='/$(project)' exe/rspec-documentation
13
+ @rsync --delete -r rspec-documentation/bundle/ docs01.bob.frl:/mnt/docs/$(project)/
14
+ @echo 'Published.'
data/README.md CHANGED
@@ -1,31 +1,27 @@
1
1
  # RSpec::Documentation
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ _RSpec Documentation_ provides a simple but powerful system for generating _Ruby_ documentation using [_RSpec_](https://rspec.info/) designed to help you ensure that all code examples in your documentation really work.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rspec/documentation`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ * Create a tree of _Markdown_ files in your project directory under `rspec-documentation/pages/`.
6
+ * Embed tests in ```` ```rspec ```` code blocks (other output formatters are available - see examples).
7
+ * Define a `subject` for each test.
8
+ * Run the provided `rspec-documentation` command.
6
9
 
7
- ## Installation
10
+ There is no _DSL_ to learn and vanilla _RSpec_ examples are used to generate inputs and outputs. No _Markdown_ language extensions are used, simply define the language of a fenced code block as `rspec` in any `.md` file and _RSpecDocumentation_ will do the rest.
8
11
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
12
+ ## Quick Example
10
13
 
11
- Install the gem and add to the application's Gemfile by executing:
14
+ The following is an example _Markdown_ file.
12
15
 
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
16
+ ````console
17
+ # An example test
14
18
 
15
- If bundler is not being used to manage dependencies, install the gem by executing:
19
+ This is a very simple test:
16
20
 
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
21
+ ```rspec
22
+ subject { 'my subject' }
23
+ it { is_expected.to eql 'my subject' }
24
+ ```
25
+ ````
18
26
 
19
- ## Usage
20
-
21
- TODO: Write usage instructions here
22
-
23
- ## Development
24
-
25
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
-
27
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
-
29
- ## Contributing
30
-
31
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rspec-documentation.
27
+ View the [full documentation](https://docs.bob.frl/rspec-documentation) (built using Rspec Documentation!) for detailed usage instructions.
@@ -2,4 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative '../lib/rspec/documentation'
5
- RSpec::Documentation.generate_documentation
5
+
6
+ documentation = RSpec::Documentation.generate_documentation
7
+
8
+ exit 1 if documentation.failed?
9
+ exit 0
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Documentation
5
- VERSION = '0.0.2'
5
+ VERSION = '0.0.4'
6
6
  end
7
7
  end
@@ -11,63 +11,13 @@ module RSpec
11
11
  class Error < StandardError; end
12
12
 
13
13
  class << self
14
- include Paintbrush
15
-
16
14
  def generate_documentation
17
- require_spec_helper
18
- page_collection.generate
19
- page_collection.flush unless failed?
20
- print_summary
21
- nil
22
- end
23
-
24
- def require_spec_helper
25
- path = Pathname.new(Dir.pwd).join('rspec-documentation/spec_helper.rb')
26
- require path if path.file?
15
+ RSpecDocumentation::Documentation.new.tap(&:generate)
27
16
  end
28
17
 
29
18
  def configure(&block)
30
19
  RSpecDocumentation.configure(&block)
31
20
  end
32
-
33
- private
34
-
35
- def print_success_summary
36
- warn(paintbrush { green("\n Created #{blue(page_paths.size)} pages.\n") })
37
- warn(paintbrush { cyan(" View your documentation here: #{white(bundle_index_path)}\n") })
38
- end
39
-
40
- def print_failure_summary
41
- page_collection.failures.each do |failure|
42
- $stderr.write(failure.message)
43
- end
44
- end
45
-
46
- def bundle_index_path
47
- RSpecDocumentation::Util.bundle_dir.glob('*.html').first.expand_path
48
- end
49
-
50
- def page_paths
51
- @page_paths ||= Pathname.new(Dir.pwd).join('rspec-documentation/pages').glob('**/*.md')
52
- end
53
-
54
- def page_collection
55
- @page_collection ||= RSpecDocumentation::PageCollection.new(page_paths: page_paths)
56
- end
57
-
58
- def failed?
59
- !page_collection.failures.empty?
60
- end
61
-
62
- def print_summary
63
- if failed?
64
- print_failure_summary
65
- else
66
- print_success_summary
67
- end
68
-
69
- nil
70
- end
71
21
  end
72
22
  end
73
23
  end
@@ -4,12 +4,25 @@ module RSpecDocumentation
4
4
  # Configures the rspec-documentation gem, allows setting a context that makes values available to each example.
5
5
  class Configuration
6
6
  def initialize
7
- @context = Context.new
7
+ @context_defined = false
8
8
  end
9
9
 
10
- def context
11
- yield @context if block_given?
12
- @context
10
+ def context_defined?
11
+ @context_defined
12
+ end
13
+
14
+ def attribution
15
+ return @attribution if defined?(@attribution)
16
+
17
+ 'Documentation generated by ' \
18
+ '<a target="_blank" href="https://github.com/bobf/rspec-documentation">rspec-documentation</a>'
19
+ end
20
+
21
+ def context(&block)
22
+ raise Error, 'RSpecDocumentation context has already been defined.' if context_defined?
23
+
24
+ @context_defined = true
25
+ ::RSpec.shared_context('__rspec_documentation', &block)
13
26
  end
14
27
  end
15
28
  end
@@ -5,8 +5,9 @@ module RSpecDocumentation
5
5
  class Document
6
6
  attr_reader :failures, :page_tree
7
7
 
8
- def initialize(document:, page_tree:)
8
+ def initialize(document:, path:, page_tree:)
9
9
  @document = document
10
+ @path = path
10
11
  @page_tree = page_tree
11
12
  @failures = []
12
13
  end
@@ -30,14 +31,17 @@ module RSpecDocumentation
30
31
  end
31
32
 
32
33
  def title
33
- # TODO: Try other methods of inferring documentation title, allow setting by configuration
34
- gem_spec&.name
34
+ gem_spec&.name || 'Documentation'
35
35
  end
36
36
 
37
37
  def version
38
38
  gem_spec&.version
39
39
  end
40
40
 
41
+ def homepage
42
+ gem_spec&.homepage
43
+ end
44
+
41
45
  def header
42
46
  RSpecDocumentation.template('header').result(binding)
43
47
  end
@@ -46,12 +50,20 @@ module RSpecDocumentation
46
50
  RSpecDocumentation.template('footer').result(binding)
47
51
  end
48
52
 
53
+ def stylesheet_bundle_href
54
+ Util.assets_root.join('bundle.css')
55
+ end
56
+
57
+ def javascript_bundle_src
58
+ Util.assets_root.join('bundle.js')
59
+ end
60
+
49
61
  private
50
62
 
51
- attr_reader :document
63
+ attr_reader :document, :path
52
64
 
53
65
  def parsed_document
54
- @parsed_document ||= ParsedDocument.new(document)
66
+ @parsed_document ||= ParsedDocument.new(document, path: path)
55
67
  end
56
68
 
57
69
  def gem_spec
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ # Generates documentation from Markdown files, main entry point to documentation generator.
5
+ class Documentation
6
+ include Paintbrush
7
+
8
+ def generate
9
+ initialize_if_empty
10
+ start
11
+ require_spec_helper
12
+ ensure_context
13
+ page_collection.generate
14
+ flush unless failed?
15
+ summary.flush
16
+ rescue RSpecDocumentation::MissingFileError => e
17
+ warn(paintbrush { red e.message })
18
+ @failed = true
19
+ end
20
+
21
+ def failed?
22
+ @failed || !page_collection.failures.empty?
23
+ end
24
+
25
+ private
26
+
27
+ def require_spec_helper
28
+ path = pwd.join('rspec-documentation/spec_helper.rb')
29
+ require path if path.file?
30
+ end
31
+
32
+ # Ensure `__rspec_documentation` shared context is always defined.
33
+ # See lib/rspec_documenation/spec.rb
34
+ def ensure_context
35
+ return if RSpecDocumentation.configuration.context_defined?
36
+
37
+ RSpecDocumentation.configuration.context {} # rubocop:disable Lint/EmptyBlock
38
+ end
39
+
40
+ def start
41
+ warn(paintbrush { white "\nRunning specs..." })
42
+ @started_at = Time.now.utc
43
+ end
44
+
45
+ def initialize_if_empty
46
+ return if Util.base_dir.exist?
47
+
48
+ ProjectInitialization.new.flush
49
+ end
50
+
51
+ def summary
52
+ @summary ||= RSpecDocumentation::Summary.new(
53
+ page_collection: page_collection,
54
+ pwd: pwd,
55
+ started_at: @started_at
56
+ )
57
+ end
58
+
59
+ def flush
60
+ page_collection.flush
61
+ stylesheet_bundle.flush
62
+ javascript_bundle.flush
63
+ end
64
+
65
+ def stylesheet_bundle
66
+ @stylesheet_bundle ||= RSpecDocumentation::StylesheetBundle.new
67
+ end
68
+
69
+ def javascript_bundle
70
+ @javascript_bundle ||= RSpecDocumentation::JavascriptBundle.new
71
+ end
72
+
73
+ def page_paths
74
+ @page_paths ||= pwd.join('rspec-documentation/pages').glob('**/*.md')
75
+ end
76
+
77
+ def page_collection
78
+ @page_collection ||= RSpecDocumentation::PageCollection.new(page_paths: page_paths)
79
+ end
80
+
81
+ def pwd
82
+ @pwd ||= Pathname.new(Dir.pwd)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ module Formatters
5
+ COLOR_CODES = [0, 1, 2, 3, 4, 5, 6, 7, 9].freeze
6
+
7
+ # Outputs a string containing ANSI color code escape sequences into HTML with attached
8
+ # classes for each matched color code. Cleans any remaining escape codes.
9
+ class Ansi
10
+ def initialize(subject:)
11
+ @subject = subject
12
+ end
13
+
14
+ def prettified_output
15
+ nil
16
+ end
17
+
18
+ def rendered_output
19
+ "<div class='ansi-html border m-1 p-4'><span>#{subbed_content}</span></div>"
20
+ end
21
+
22
+ def render_raw?
23
+ false
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :subject
29
+
30
+ def subbed_content
31
+ COLOR_CODES.reduce(subbed_hex_codes) do |string, color_code|
32
+ string&.gsub("\e[3#{color_code}m", "</span><span class='ansi-color-#{color_code}'>")
33
+ &.gsub("\e[9#{color_code}m", "</span><span class='ansi-bright ansi-color-#{color_code}'>")
34
+ &.gsub(/\e\[38;5;([0-9]{1,3})m/, "</span><span class='ansi-color-\\1'>")
35
+ &.gsub("\e[0m", "</span><span class='ansi-color-reset'>")
36
+ end&.gsub(/\e\[[0-9;]+m/, '')
37
+ end
38
+
39
+ def subbed_hex_codes
40
+ subject&.gsub(/\e\[38;2;([0-9]+);([0-9]+);([0-9]+)m/, '</span><span style="color: rgb(\1,\2,\3)">')
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ module Formatters
5
+ # Beautifies HTML received from a `subject`, renders the raw subject to be inserted directly
6
+ # into the output document.
7
+ class Html
8
+ def initialize(subject:)
9
+ @subject = subject
10
+ end
11
+
12
+ def prettified_output
13
+ formatter = Rouge::Formatters::HTML.new
14
+ lexer = Rouge::Lexers::HTML.new
15
+ formatter.format(lexer.lex(HtmlBeautifier.beautify(subject)))
16
+ end
17
+
18
+ def rendered_output
19
+ subject
20
+ end
21
+
22
+ def render_raw?
23
+ true
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :subject
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ module Formatters
5
+ # Produces prettified JSON to from an RSpec `subject` value.
6
+ class Json
7
+ def initialize(subject:)
8
+ @subject = subject
9
+ end
10
+
11
+ def prettified_output
12
+ nil
13
+ end
14
+
15
+ def rendered_output
16
+ formatter = Rouge::Formatters::HTML.new
17
+ lexer = Rouge::Lexers::JSON.new
18
+ formatter.format(lexer.lex(JSON.pretty_generate(JSON.parse(subject))))
19
+ rescue JSON::ParserError => e
20
+ raise Error, "Expected JSON for:\n#{subject}\n\nParser Error: #{e}"
21
+ end
22
+
23
+ def render_raw?
24
+ false
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :subject
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ module Formatters
5
+ # Default formatter for all RSpec examples. Used by all examples to generate the "Spec" tab
6
+ # content, i.e. the original source of the example code.
7
+ class Ruby
8
+ def initialize(subject:)
9
+ @subject = subject
10
+ end
11
+
12
+ def prettified_output
13
+ nil
14
+ end
15
+
16
+ def rendered_output
17
+ formatter = Rouge::Formatters::HTML.new
18
+ lexer = Rouge::Lexers::Ruby.new
19
+ formatter.format(lexer.lex(subject.inspect))
20
+ end
21
+
22
+ def render_raw?
23
+ false
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :subject
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ module Formatters
5
+ # Produces prettified YAML to from an RSpec `subject` value.
6
+ class Yaml
7
+ def initialize(subject:)
8
+ @subject = subject
9
+ end
10
+
11
+ def prettified_output
12
+ nil
13
+ end
14
+
15
+ def rendered_output
16
+ formatter = Rouge::Formatters::HTML.new
17
+ lexer = Rouge::Lexers::YAML.new
18
+ formatter.format(lexer.lex(YAML.safe_load(subject, permitted_classes: permitted_classes).to_yaml))
19
+ rescue Psych::SyntaxError => e
20
+ raise Error, "Expected YAML for:\n#{subject}\n\nSyntax Error: #{e}"
21
+ end
22
+
23
+ def render_raw?
24
+ false
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :subject
30
+
31
+ def permitted_classes
32
+ [Symbol, Date, Time, DateTime]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'formatters/ruby'
4
+ require_relative 'formatters/html'
5
+ require_relative 'formatters/ansi'
6
+ require_relative 'formatters/json'
7
+ require_relative 'formatters/yaml'
8
+
9
+ module RSpecDocumentation
10
+ # Provides a set of formatters for rendering the value of a `subject` in an RSpec example into
11
+ # a useful format according to the language specified in the relevant Markdown code block, e.g.
12
+ # `rspec:html` will use the `Html` formatter to render beautified HTML source and the rendered
13
+ # output.
14
+ module Formatters
15
+ def self.with_translated_html_entities(content)
16
+ content&.gsub("\n", '<br/>')
17
+ &.gsub(' ', '&nbsp;&nbsp;')
18
+ end
19
+ end
20
+ end
@@ -14,24 +14,24 @@ module RSpecDocumentation
14
14
  Kramdown::Document.new(tabbed_spec, input: 'html').root
15
15
  end
16
16
 
17
- def html_source
18
- return nil unless spec.format == :html
19
-
17
+ def code_source
20
18
  formatter = Rouge::Formatters::HTML.new
21
- lexer = Rouge::Lexers::HTML.new
22
-
23
- formatter.format(lexer.lex(HtmlBeautifier.beautify(spec.described_object)))
19
+ lexer = Rouge::Lexers::Ruby.new
20
+ Formatters.with_translated_html_entities(formatter.format(lexer.lex(spec.source)))
24
21
  end
25
22
 
26
- def code_source
27
- formatted_ruby(spec.source)
23
+ def prettified_output
24
+ Formatters.with_translated_html_entities(formatter.prettified_output)
28
25
  end
29
26
 
30
- def rendered_result
31
- return spec.described_object if spec.format == :html
32
- return AnsiHTML.new(spec.described_object).render if spec.format == :ansi
27
+ def rendered_output
28
+ return formatter.rendered_output if render_raw?
29
+
30
+ Formatters.with_translated_html_entities(formatter.rendered_output)
31
+ end
33
32
 
34
- formatted_ruby(spec.described_object.inspect)
33
+ def render_raw?
34
+ formatter.render_raw?
35
35
  end
36
36
 
37
37
  def element_id
@@ -42,14 +42,17 @@ module RSpecDocumentation
42
42
 
43
43
  attr_reader :spec
44
44
 
45
- def tabbed_spec
46
- RSpecDocumentation.template('tabbed_spec').result(binding)
45
+ def formatter
46
+ @formatter ||= {
47
+ html: Formatters::Html,
48
+ ansi: Formatters::Ansi,
49
+ json: Formatters::Json,
50
+ yaml: Formatters::Yaml
51
+ }.fetch(spec.format, Formatters::Ruby).new(subject: spec.subject)
47
52
  end
48
53
 
49
- def formatted_ruby(code)
50
- formatter = Rouge::Formatters::HTML.new
51
- lexer = Rouge::Lexers::Ruby.new
52
- formatter.format(lexer.lex(code))
54
+ def tabbed_spec
55
+ RSpecDocumentation.template('tabbed_spec').result(binding)
53
56
  end
54
57
  end
55
58
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpecDocumentation
4
+ # Compiles Javascript assets into a single file.
5
+ class JavascriptBundle
6
+ def flush
7
+ Util.bundle_dir.join('assets').mkpath
8
+ javascript_bundle_path.write(RSpecDocumentation.template(:layout, :js).result(binding))
9
+ end
10
+
11
+ private
12
+
13
+ def javascript_bundle_path
14
+ Util.bundle_dir.join('assets/bundle.js')
15
+ end
16
+ end
17
+ end