bhook 0.1.0 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 004e13098155733cadddffee89a4085b4c7dc78fafa28de82b4266cd86c95eab
4
- data.tar.gz: aa6a9773afd270b0d63f230142b3ac86a3f90719b6602a7ae26cee712b36ffff
3
+ metadata.gz: b4ef3049d516cd681eac21ac34923cf9cdd292cbb79ca238d7228e1a18a9a323
4
+ data.tar.gz: 942754c6193f0e19d1b2dc028aa13e9033e7d2e4f5a01e3edb76248ce2d1e3f6
5
5
  SHA512:
6
- metadata.gz: 757d1a3bcabc583116a5d02b41beb198f19dc891cb3ce948482614bd77f7a18ae5082ee5e3e535ee777739b030d25887ae7d1b8c3ccaa566943035e7ca51cd2e
7
- data.tar.gz: e41a385694dabe87e08d21fa51a5d0091028b7317d81f48b107e2a73797d8b9eacc1eafdf52a42715149706ecbe30c604a1aab7f3cd39e3147a767a4fc6ddb85
6
+ metadata.gz: cb421ebe8b1ea40155b8fec5139d249b99c99bdc17f44587b07d4af8824a2519ca3edba0134f1029475df2be577da5f140149a0a11d7ea05273de23734c2fcc3
7
+ data.tar.gz: 9563f8a81b32da179e8f4582f36dfa619076237fe64880fdd3047feafc7f89826bc8098e884ce8ef3c59afc35c155d882d709a74d9e41cf54936b0af2fd21862
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bhook (0.1.0)
4
+ bhook (0.1.3)
5
5
  git (~> 1.10)
6
6
  kramdown (~> 2.3)
7
7
  listen (~> 3.7)
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Bhook
2
2
 
3
- Bhook is a static bliki generator.
3
+ Bhook is a static website generator that works off a git repo containing a markdown file based wiki, like for example, the [India Startup Wiki](https://gitlab.com/india-startups/wiki).
4
+
5
+ I use this to create [HTML versions of the wiki](https://sidu.in/wiki/startups) and of [my essays](https://sidu.in/essays/) that I can publish.
4
6
 
5
7
  ## Installation
6
8
 
@@ -10,17 +12,32 @@ Install it yourself as:
10
12
 
11
13
  ## Usage
12
14
 
13
- TODO: Write usage instructions here
15
+ Getting help:
14
16
 
15
- ## Development
17
+ $ bhook --help
18
+ Bhook version 0.1.2
19
+ Usage: bhook --source /source/path --output /output/path
20
+ -s, --source=SOURCE Path to version controlled directory containing source md files
21
+ -o, --output=OUTPUT Path to directory where output files are to be generated
22
+ -w, --watch Continuously watch the source directory for changes and generate output
23
+ -v, --verbose Print detailed information about files as they are processed
24
+ -t, --theme=PATH Path to directory containing theme files to use when generating html
25
+ --generate-theme=PATH Generate a baseline theme that you can then modify to your needs
26
+ -h, --help Prints this help
27
+
28
+ How I use it:
16
29
 
17
- 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.
30
+ ➜ essays git:(main) bhook -s . -o /tmp/out -t /tmp/out/theme -w -v
31
+
32
+ ## Development
18
33
 
19
- 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).
34
+ 1. `git clone --recursive git@gitlab.com:kaiwren/bhook.git`
35
+ 2. After checking out the repo, run `bundle install` to install dependencies.
36
+ 4. Then, run `bundle exec rake` to run the specs and sorbet typechecking.
20
37
 
21
38
  ## Contributing
22
39
 
23
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/bhook.
40
+ Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/kaiwren/bhook.
24
41
 
25
42
  ## License
26
43
 
data/bin/bhook CHANGED
@@ -5,7 +5,29 @@ require 'bundler/setup'
5
5
  require 'bhook'
6
6
 
7
7
  puts "Bhook version #{Bhook::VERSION}"
8
- args = Bhook::ArgsParser.new(ARGV).parse!
9
- workspace = Bhook::Workspace.new(args.source, args.output)
8
+ args = Bhook::ArgsParser.new(ARGV).parse
9
+
10
+ if args.verbose
11
+ Bhook::L.level = Logger::DEBUG
12
+ else
13
+ Bhook::L.level = Logger::INFO
14
+ end
15
+
16
+ if args.generate_theme
17
+ Bhook::ThemeGenerator.new(args.generate_theme).generate!
18
+ exit
19
+ end
20
+
21
+ workspace = Bhook::Workspace.new(args.source, args.output, args.theme)
22
+
23
+ if args.benchmark
24
+ require 'benchmark'
25
+ n = 10
26
+ Benchmark.bmbm do |bench|
27
+ Bhook::L.level = Logger::WARN
28
+ bench.report("Generate HTML #{n} times") { n.times { workspace.process! } }
29
+ end
30
+ exit
31
+ end
10
32
 
11
33
  args.watch ? workspace.watch! : workspace.process!
@@ -1,23 +1,30 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
1
4
  module Bhook
2
5
  class ArgsParser
3
- Options = Struct.new(:source, :output, :watch)
6
+ extend T::Sig
7
+
8
+ Options = Struct.new(:source, :output, :watch, :verbose, :theme, :generate_theme, :benchmark)
4
9
 
5
10
  def initialize(argv)
6
- @args = Options.new(nil, nil, false)
11
+ @args = Options.new(nil, nil, false, false, nil, nil, false)
7
12
  @argv = argv.clone
8
13
  @opt_parser = build_opt_parser
9
14
  end
10
15
 
11
- def parse!
16
+ def parse
12
17
  begin
13
- @opt_parser.parse!(@argv)
14
- rescue OptionParser::InvalidOption => e
18
+ @opt_parser.parse(@argv)
19
+ rescue OptionParser::ParseError => e
15
20
  puts
16
21
  puts "Error! #{e.message}"
17
22
  puts
23
+ puts @opt_parser
24
+ exit
18
25
  end
19
-
20
- if !@argv.empty? || (!@args.source || !@args.output)
26
+
27
+ if source_or_output_paths_missing? && generate_theme_missing?
21
28
  puts @opt_parser
22
29
  exit
23
30
  end
@@ -25,26 +32,59 @@ module Bhook
25
32
  end
26
33
 
27
34
  private
35
+
36
+ def source_or_output_paths_missing?
37
+ !@args.source || !@args.output
38
+ end
39
+
40
+ def generate_theme_missing?
41
+ !@args.generate_theme
42
+ end
43
+
28
44
  def build_opt_parser
29
45
  OptionParser.new do |opts|
30
46
  opts.banner = "Usage: bhook --source /source/path --output /output/path"
31
47
 
32
48
  opts.on("-sSOURCE", "--source=SOURCE",
33
- String, "Path to version controlled directory containing source md files") do |s|
34
- @args.source = s
49
+ String, "Path to version controlled directory containing source md files") do |source_path|
50
+ @args.source = source_path
35
51
  end
36
52
 
37
53
  opts.on("-oOUTPUT", "--output=OUTPUT",
38
- String, "Path to directory where output files are to be generated") do |o|
39
- @args.output = o
54
+ String, "Path to directory where output files are to be generated") do |out_path|
55
+ @args.output = out_path
40
56
  end
41
57
 
42
58
  opts.on("-w", "--watch",
43
59
  FalseClass,
44
- "Continuously watch the source directory for changes and generate output") do |w|
60
+ "Continuously watch the source directory for changes and generate output") do
45
61
  @args.watch = true
46
62
  end
47
63
 
64
+ opts.on("-v", "--verbose",
65
+ FalseClass,
66
+ "Print detailed information about files as they are processed") do
67
+ @args.verbose = true
68
+ end
69
+
70
+ opts.on("-tPATH", "--theme=PATH",
71
+ String,
72
+ "Path to directory containing theme files to use when generating html") do |path|
73
+ @args.theme = path
74
+ end
75
+
76
+ opts.on("--generate-theme=PATH",
77
+ String,
78
+ "Generate a baseline theme that you can then modify to your needs") do |path|
79
+ @args.generate_theme = path
80
+ end
81
+
82
+ opts.on("--benchmark",
83
+ FalseClass,
84
+ "Run a performance benchmark for the specified source") do
85
+ @args.benchmark = true
86
+ end
87
+
48
88
  opts.on("-h", "--help", "Prints this help") do
49
89
  puts opts
50
90
  exit
@@ -16,7 +16,7 @@ module Bhook
16
16
  def convert_a(el, indent)
17
17
  href_path = el.attr['href']
18
18
  if valid_relative_md_link?(href_path)
19
- puts "Found link: #{href_path}"
19
+ L.debug "Found link: #{href_path}"
20
20
  el.attr['href'].gsub!(/\.md/, '.html')
21
21
  end
22
22
  super(el, indent)
@@ -1,62 +1,61 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Bhook
5
5
  class Directory
6
+ extend T::Sig
7
+
6
8
  GIT_DIR = '.git'
7
9
  MD_EXT = '.md'
8
10
 
9
- attr_reader :sub_dirs, :md_files
10
-
11
- def initialize(src_path, git = nil)
11
+ sig { params(src_path: Pathname, out_path: Pathname, git: Git::Base).void }
12
+ def initialize(src_path, out_path, git)
12
13
  @src_path = src_path
14
+ @out_path = T.let(out_path.join(src_path.basename), Pathname)
13
15
  @git = git
14
- @sub_dirs = []
15
- @md_files = []
16
+ @sub_dirs = T.let([], T::Array[Directory])
17
+ @md_files = T.let([], T::Array[MdFile])
16
18
  build_next_level_nodes
17
19
  end
18
20
 
19
- def root_dir_for_a_commit?
20
- !@git
21
- end
22
-
23
- def write!(out_path)
24
- dir_path = if root_dir_for_a_commit?
25
- out_path
26
- else
27
- File.join(out_path, @src_path.basename)
28
- end
29
-
30
- FileUtils.mkdir_p(dir_path, verbose: true)
31
- @sub_dirs.each { |dir| dir.write!(dir_path) }
32
- @md_files.each { |file| file.write!(dir_path) }
21
+ sig { params(theme: Theme).void }
22
+ def write!(theme)
23
+ FileUtils.mkdir_p(@out_path)
24
+ L.debug("mkdir: #{@out_path}")
25
+ @sub_dirs.each { |dir| dir.write!(theme) }
26
+ @md_files.map do |file|
27
+ Thread.new { file.write!(theme) }
28
+ end.each do |thread|
29
+ thread.join
30
+ end
33
31
  end
34
-
32
+
33
+ sig { returns(T::Array[MdFile]) }
35
34
  def all_md_files
36
35
  @md_files + @sub_dirs.map(&:all_md_files).flatten
37
36
  end
38
37
 
38
+ sig { returns(String) }
39
39
  def to_s
40
40
  @src_path.to_s
41
41
  end
42
-
42
+
43
43
  private
44
44
 
45
+ sig { void }
45
46
  def build_next_level_nodes
46
- if root_dir_for_a_commit?
47
- @git = Git.open(@src_path)
48
- end
49
-
50
- @sub_dirs = @src_path.children.map do |child|
51
- if child.directory? && child.basename.to_s != GIT_DIR
52
- Directory.new(child, @git)
47
+ children = @src_path.children
48
+ children.delete(@src_path.join(GIT_DIR))
49
+
50
+ file_threads = []
51
+ children.each do |child_path|
52
+ if child_path.directory?
53
+ @sub_dirs << Directory.new(child_path, @out_path, @git)
54
+ elsif child_path.extname == MD_EXT
55
+ file_threads << Thread.new { MdFile.new(child_path, @out_path, @git) }
53
56
  end
54
- end.compact
55
- @md_files = @src_path.children.select do |child|
56
- !child.directory? && child.extname == MD_EXT
57
- end.map do |child|
58
- MdFile.new(child, @git)
59
- end.compact
57
+ end
58
+ file_threads.each { |thread| @md_files << thread.value }
60
59
  end
61
60
  end
62
61
  end
@@ -0,0 +1,8 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Bhook
5
+ L = Logger.new(STDOUT, formatter: proc {|severity, datetime, progname, msg|
6
+ "#{Thread.current.object_id} #{msg}\n"
7
+ })
8
+ end
data/lib/bhook/md_file.rb CHANGED
@@ -1,50 +1,47 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Bhook
5
5
  class MdFile
6
6
  extend T::Sig
7
- PAGE_TEMPLATE = File.read(File.join(File.dirname(__FILE__), 'theme', 'page.erb'))
8
- AFTER_H1_TEMPLATE = File.read(File.join(File.dirname(__FILE__), 'theme', '_after_h1.erb'))
9
-
10
- def initialize(src_file_path, git)
7
+
8
+ PAGE_TEMPLATE = T.let(File.read(Bhook::PAGE_TEMPLATE_PATH), String)
9
+ AFTER_H1_TEMPLATE = T.let(File.read(Bhook::AFTER_H1_TEMPLATE_PATH), String)
10
+
11
+ sig { returns(Pathname) }
12
+ attr_reader :src_file_path
13
+
14
+ sig { params(src_file_path: Pathname, out_path: Pathname, git: Git::Base).void }
15
+ def initialize(src_file_path, out_path, git)
16
+ L.debug "Reading: #{src_file_path}"
11
17
  @md = T.let(File.read(src_file_path), String)
12
- @src_file_path = src_file_path.expand_path
13
- file_meta_data = git.lib.send(:command, 'log',
14
- '-n 1',
15
- '--pretty=format:%ad|%h',
16
- '--date=short',
17
- '--',
18
- @src_file_path)
19
- @src_file_date, @src_file_sha = file_meta_data.split('|')
18
+ @src_file_path = src_file_path
19
+ @out_path = out_path
20
+ src_file_date, src_file_sha = git.lib.send(:command, 'log',
21
+ '-n 1',
22
+ '--pretty=format:%ad|%h',
23
+ '--date=short',
24
+ '--',
25
+ @src_file_path).split('|')
26
+ @src_file_date = T.let(src_file_date, T.nilable(String))
27
+ @src_file_sha = T.let(src_file_sha, T.nilable(String))
20
28
  end
21
29
 
22
- sig { returns(Pathname) }
23
- attr_reader :src_file_path
30
+ sig { params(theme: Bhook::Theme).void }
31
+ def write!(theme)
32
+ out_file_name = @src_file_path.basename.sub(/\.md$/, '.html')
33
+ out_file_path = @out_path.join(out_file_name)
24
34
 
25
- sig { params(out_path: String).void }
26
- def write!(out_path)
27
- out_file_name = File.basename(@src_file_path).gsub(/\.md$/, '.html')
28
- out_file_path = File.join(out_path, out_file_name)
29
- src_file_sha = @src_file_sha
30
- src_file_date = @src_file_date
31
- src_title = ''
32
- puts "Parsing: #{@src_file_sha} #{out_file_path}"
33
- after_h1_strategy = ->(binding_instance) { ERB.new(AFTER_H1_TEMPLATE, trim_mode: '-').result(binding_instance) }
35
+ L.debug "Processing: #{@src_file_sha || 'unversioned'} #{@src_file_path}"
36
+ rendered_page = theme.render_page(@md, @src_file_sha, @src_file_date)
34
37
 
35
- doc = Kramdown::Document.new(@md)
36
- output, warnings = Converter::Html.convert(doc.root, doc.options.merge(
37
- after_h1_strategy: after_h1_strategy,
38
- h1_callback: ->(str) { src_title = str }
39
- ))
40
- rendered_page = ERB.new(PAGE_TEMPLATE, trim_mode: '-').result(binding)
41
- puts "Writing: #{@src_file_sha} #{out_file_path}"
38
+ L.debug "Writing: #{@src_file_sha} #{out_file_path}"
42
39
  File.write(out_file_path, rendered_page)
43
40
  end
44
41
 
45
42
  sig { returns(String) }
46
43
  def to_s
47
- @src_file_path
44
+ @src_file_path.to_s
48
45
  end
49
46
  end
50
47
  end
@@ -0,0 +1,13 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Bhook
5
+ class RootDirectory < Directory
6
+ extend T::Sig
7
+
8
+ sig { params(src_path: Pathname, out_path: Pathname).void }
9
+ def initialize(src_path, out_path)
10
+ super(src_path, out_path, Git.open(src_path))
11
+ end
12
+ end
13
+ end
@@ -4,4 +4,3 @@ href="https://twitter.com/intent/tweet?text=<%= CGI.escape(src_title) -%>&via=po
4
4
  <a class="twitter-follow-button" href="https://twitter.com/ponnappa">Follow @ponnappa</a>
5
5
  <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
6
6
  </div>
7
-
@@ -0,0 +1,28 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Bhook
5
+ class Theme
6
+ extend T::Sig
7
+
8
+ sig { params(theme_path: String).void }
9
+ def initialize(theme_path)
10
+ @page_template = T.let(File.read(File.join(theme_path, 'page.erb')), String)
11
+ @after_h1_template = T.let(File.read(File.join(theme_path, '_after_h1.erb')), String)
12
+ strategy = ->(binding_instance) { ERB.new(@after_h1_template, trim_mode: '-').result(binding_instance) }
13
+ @after_h1_strategy = T.let(strategy, T.proc.params(binding_instance: Binding).returns(String))
14
+ end
15
+
16
+ sig { params(md: String, src_file_sha: T.nilable(String), src_file_date: T.nilable(String)).returns(String) }
17
+ def render_page(md, src_file_sha, src_file_date)
18
+ src_title = T.let('', String)
19
+
20
+ doc = Kramdown::Document.new(md)
21
+ output, warnings = Converter::Html.convert(doc.root, doc.options.merge(
22
+ after_h1_strategy: @after_h1_strategy,
23
+ h1_callback: ->(str) { src_title = str }
24
+ ))
25
+ ERB.new(@page_template, trim_mode: '-').result(binding)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Bhook
5
+ class ThemeGenerator
6
+ extend T::Sig
7
+
8
+ sig {params(output_path: String).void}
9
+ def initialize(output_path)
10
+ @output_path = T.let(File.join(output_path, 'theme'), String)
11
+ @template_files = T.let([Bhook::PAGE_TEMPLATE_PATH,
12
+ Bhook::AFTER_H1_TEMPLATE_PATH], T::Array[String])
13
+ end
14
+
15
+ sig {void}
16
+ def generate!
17
+ FileUtils.mkdir_p(@output_path, verbose: true)
18
+ FileUtils.cp(@template_files, @output_path, verbose: true)
19
+ end
20
+ end
21
+ end
data/lib/bhook/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Bhook
5
- VERSION = '0.1.0'
5
+ VERSION = '0.1.3'
6
6
  end
@@ -5,26 +5,27 @@ module Bhook
5
5
  class Workspace
6
6
  extend T::Sig
7
7
 
8
- sig { params(src_path: String, out_path: String).void }
9
- def initialize(src_path, out_path)
10
- @src_path = src_path
11
- @out_path = out_path
8
+ sig { params(src_path: String, out_path: String, theme_path: String).void }
9
+ def initialize(src_path, out_path, theme_path)
10
+ @src_path = T.let(Pathname.new(src_path).expand_path, Pathname)
11
+ @out_path = T.let(Pathname.new(out_path).expand_path, Pathname)
12
+ @theme = T.let(Theme.new(theme_path), Bhook::Theme)
12
13
  end
13
14
 
14
15
  sig { void }
15
- def process!
16
- root = root_dir
17
- root.write!(@out_path)
16
+ def process!
17
+ root_dir.write!(@theme)
18
+ L.info "Done!"
18
19
  end
19
20
 
20
21
  sig { void }
21
22
  def watch!
22
23
  process!
23
- puts
24
- puts "Watching #{@src_path} for changes..."
25
- listener = Listen.to(@src_path, File.join(@src_path, '.git')) do |_modified, _added, _removed|
24
+
25
+ L.info "Watching: #{@src_path} for changes..."
26
+ listener = Listen.to(@src_path.to_s, File.join(@src_path.to_s, '.git')) do |_modified, _added, _removed|
27
+ L.info "Detected changes..."
26
28
  process!
27
- puts "-----\n"
28
29
  end
29
30
  listener.start
30
31
  sleep
@@ -34,12 +35,11 @@ module Bhook
34
35
  def all_md_files
35
36
  root_dir.all_md_files
36
37
  end
37
-
38
- private
39
-
40
- sig { returns(Bhook::Directory) }
38
+
39
+ private
40
+ sig { returns(Bhook::RootDirectory) }
41
41
  def root_dir
42
- Directory.new(Pathname.new(@src_path))
42
+ RootDirectory.new(@src_path, @out_path)
43
43
  end
44
44
  end
45
45
  end
data/lib/bhook.rb CHANGED
@@ -6,17 +6,29 @@ require 'fileutils'
6
6
  require 'pathname'
7
7
  require 'erb'
8
8
  require 'optparse'
9
+ require 'logger'
9
10
  require 'sorbet-runtime'
10
11
  require 'git'
11
12
  require 'kramdown'
12
13
  require 'listen'
14
+
15
+ module Bhook
16
+ extend T::Sig
17
+
18
+ THEME_DIR_PATH = T.let(File.join(File.dirname(__FILE__), 'bhook', 'theme'), String)
19
+ PAGE_TEMPLATE_PATH = T.let(File.join(THEME_DIR_PATH, 'page.erb'), String)
20
+ AFTER_H1_TEMPLATE_PATH = T.let(File.join(THEME_DIR_PATH, '_after_h1.erb'), String)
21
+
22
+ class Error < StandardError; end
23
+ end
24
+
13
25
  require_relative 'bhook/version'
26
+ require_relative 'bhook/logger'
14
27
  require_relative 'bhook/args_parser'
28
+ require_relative 'bhook/theme_generator'
29
+ require_relative 'bhook/theme'
15
30
  require_relative 'bhook/converter/html'
16
31
  require_relative 'bhook/directory'
32
+ require_relative 'bhook/root_directory'
17
33
  require_relative 'bhook/md_file'
18
34
  require_relative 'bhook/workspace'
19
-
20
- module Bhook
21
- class Error < StandardError; end
22
- end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bhook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sidu Ponnappa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-12 00:00:00.000000000 Z
11
+ date: 2022-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -171,9 +171,13 @@ files:
171
171
  - lib/bhook/args_parser.rb
172
172
  - lib/bhook/converter/html.rb
173
173
  - lib/bhook/directory.rb
174
+ - lib/bhook/logger.rb
174
175
  - lib/bhook/md_file.rb
176
+ - lib/bhook/root_directory.rb
177
+ - lib/bhook/theme.rb
175
178
  - lib/bhook/theme/_after_h1.erb
176
179
  - lib/bhook/theme/page.erb
180
+ - lib/bhook/theme_generator.rb
177
181
  - lib/bhook/version.rb
178
182
  - lib/bhook/workspace.rb
179
183
  - sorbet/config