herb 0.0.1 → 0.1.0

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.
Files changed (108) hide show
  1. checksums.yaml +5 -5
  2. data/{LICENSE → LICENSE.txt} +4 -3
  3. data/Makefile +121 -0
  4. data/README.md +102 -107
  5. data/Rakefile +184 -0
  6. data/exe/herb +5 -0
  7. data/ext/herb/error_helpers.c +302 -0
  8. data/ext/herb/error_helpers.h +15 -0
  9. data/ext/herb/extconf.rb +75 -0
  10. data/ext/herb/extension.c +110 -0
  11. data/ext/herb/extension.h +6 -0
  12. data/ext/herb/extension_helpers.c +117 -0
  13. data/ext/herb/extension_helpers.h +24 -0
  14. data/ext/herb/nodes.c +936 -0
  15. data/ext/herb/nodes.h +12 -0
  16. data/herb.gemspec +49 -0
  17. data/lib/herb/ast/node.rb +61 -0
  18. data/lib/herb/ast/nodes.rb +1542 -0
  19. data/lib/herb/ast.rb +6 -0
  20. data/lib/herb/cli.rb +164 -0
  21. data/lib/herb/errors.rb +352 -0
  22. data/lib/herb/lex_result.rb +20 -0
  23. data/lib/herb/libherb/array.rb +48 -0
  24. data/lib/herb/libherb/ast_node.rb +47 -0
  25. data/lib/herb/libherb/buffer.rb +53 -0
  26. data/lib/herb/libherb/extract_result.rb +17 -0
  27. data/lib/herb/libherb/lex_result.rb +29 -0
  28. data/lib/herb/libherb/libherb.rb +49 -0
  29. data/lib/herb/libherb/parse_result.rb +17 -0
  30. data/lib/herb/libherb/token.rb +43 -0
  31. data/lib/herb/libherb.rb +32 -0
  32. data/lib/herb/location.rb +42 -0
  33. data/lib/herb/parse_result.rb +26 -0
  34. data/lib/herb/position.rb +36 -0
  35. data/lib/herb/project.rb +361 -0
  36. data/lib/herb/range.rb +40 -0
  37. data/lib/herb/result.rb +21 -0
  38. data/lib/herb/token.rb +43 -0
  39. data/lib/herb/token_list.rb +11 -0
  40. data/lib/herb/version.rb +5 -0
  41. data/lib/herb.rb +21 -68
  42. data/src/analyze.c +989 -0
  43. data/src/analyze_helpers.c +241 -0
  44. data/src/analyzed_ruby.c +35 -0
  45. data/src/array.c +137 -0
  46. data/src/ast_node.c +81 -0
  47. data/src/ast_nodes.c +866 -0
  48. data/src/ast_pretty_print.c +588 -0
  49. data/src/buffer.c +199 -0
  50. data/src/errors.c +740 -0
  51. data/src/extract.c +110 -0
  52. data/src/herb.c +103 -0
  53. data/src/html_util.c +143 -0
  54. data/src/include/analyze.h +36 -0
  55. data/src/include/analyze_helpers.h +43 -0
  56. data/src/include/analyzed_ruby.h +33 -0
  57. data/src/include/array.h +33 -0
  58. data/src/include/ast_node.h +35 -0
  59. data/src/include/ast_nodes.h +303 -0
  60. data/src/include/ast_pretty_print.h +17 -0
  61. data/src/include/buffer.h +36 -0
  62. data/src/include/errors.h +125 -0
  63. data/src/include/extract.h +20 -0
  64. data/src/include/herb.h +32 -0
  65. data/src/include/html_util.h +13 -0
  66. data/src/include/io.h +9 -0
  67. data/src/include/json.h +28 -0
  68. data/src/include/lexer.h +13 -0
  69. data/src/include/lexer_peek_helpers.h +23 -0
  70. data/src/include/lexer_struct.h +32 -0
  71. data/src/include/location.h +25 -0
  72. data/src/include/macros.h +10 -0
  73. data/src/include/memory.h +12 -0
  74. data/src/include/parser.h +22 -0
  75. data/src/include/parser_helpers.h +33 -0
  76. data/src/include/position.h +22 -0
  77. data/src/include/pretty_print.h +53 -0
  78. data/src/include/prism_helpers.h +18 -0
  79. data/src/include/range.h +23 -0
  80. data/src/include/ruby_parser.h +6 -0
  81. data/src/include/token.h +25 -0
  82. data/src/include/token_matchers.h +21 -0
  83. data/src/include/token_struct.h +51 -0
  84. data/src/include/util.h +25 -0
  85. data/src/include/version.h +6 -0
  86. data/src/include/visitor.h +11 -0
  87. data/src/io.c +30 -0
  88. data/src/json.c +205 -0
  89. data/src/lexer.c +284 -0
  90. data/src/lexer_peek_helpers.c +59 -0
  91. data/src/location.c +41 -0
  92. data/src/main.c +162 -0
  93. data/src/memory.c +53 -0
  94. data/src/parser.c +704 -0
  95. data/src/parser_helpers.c +161 -0
  96. data/src/position.c +33 -0
  97. data/src/pretty_print.c +242 -0
  98. data/src/prism_helpers.c +50 -0
  99. data/src/range.c +38 -0
  100. data/src/ruby_parser.c +47 -0
  101. data/src/token.c +194 -0
  102. data/src/token_matchers.c +32 -0
  103. data/src/util.c +128 -0
  104. data/src/visitor.c +321 -0
  105. metadata +126 -82
  106. data/test/helper.rb +0 -7
  107. data/test/helpers_test.rb +0 -25
  108. data/test/parsing_test.rb +0 -110
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5c394bc2c2281a98fffdbd20598cf1b8fb14c710
4
- data.tar.gz: a3179a63d031f7599274f144ef7d846518a0bd96
2
+ SHA256:
3
+ metadata.gz: 7181a99a7c115d405967410785ab43baae8a4b135224160b49e653e7150774a4
4
+ data.tar.gz: 915521c5e89f18dd4ee0197f0518d59749ba6f19f4452662400c45c8706ac364
5
5
  SHA512:
6
- metadata.gz: 02bd3e967c8d5433d141d4c4fb6c84c6610c2ca280413016def1280a7b4b77520289e582c070d030455f3a66b714cab34f292c46c7de94199e95ab8356d90b40
7
- data.tar.gz: d2c7bfbd62d6188b5bbf7741b90113ffef0945ae7724f2e92ae98efc2d099a75496a3b4215836dc09bdd3a688776f547e46962a8457605eb219025bd34511c90
6
+ metadata.gz: 0aa709590f400e64270e3c20ebf598ab7be7195812415e90426f0380a0237780f171e4cd9c7583acf3ab03edf7cd8f0166873f82633c75ed1b35c27e92a07073
7
+ data.tar.gz: 3ddddf73d9303d9807a41acbcf6fc09a00983bdeffcfa732715e1f921d2edb4ef2f7b1bd4bd9b4d75b21473f75bef1cfd547caba84e310db05f7c287186eec39
@@ -1,5 +1,6 @@
1
- Copyright (c) 2016 Francesco Rodriguez
2
- Copyright (c) 2011-2016 Michel Martens
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Marco Roth
3
4
 
4
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
6
  of this software and associated documentation files (the "Software"), to deal
@@ -17,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- THE SOFTWARE.
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,121 @@
1
+ exec = herb
2
+ test_exec = run_herb_tests
3
+
4
+ sources = $(wildcard src/*.c) $(wildcard src/**/*.c)
5
+ headers = $(wildcard src/*.h) $(wildcard src/**/*.h)
6
+ objects = $(sources:.c=.o)
7
+
8
+ extension_sources = $(wildcard ext/**/*.c)
9
+ extension_headers = $(wildcard ext/**/*.h)
10
+ extension_objects = $(extension_sources:.o)
11
+
12
+ prism_objects = $(filter-out src/main.c, $(sources))
13
+
14
+ project_files = $(sources) $(headers)
15
+ extension_files = $(extension_sources) $(extension_headers)
16
+ nodejs_extension_files = $(wildcard node/**/*.cpp) $(wildcard node/**/*.h) $(wildcard node/**/*.hpp)
17
+ project_and_extension_files = $(project_files) $(extension_files) $(nodejs_extension_files)
18
+
19
+ test_sources = $(wildcard test/**/*.c)
20
+ test_objects = $(test_sources:.c=.o)
21
+ non_main_objects = $(filter-out src/main.o, $(objects))
22
+
23
+ soext ?= $(shell ruby -e 'puts RbConfig::CONFIG["DLEXT"]')
24
+ lib_name = $(build_dir)/lib$(exec).$(soext)
25
+ static_lib_name = $(build_dir)/lib$(exec).a
26
+ ruby_extension = ext/herb/$(lib_name)
27
+
28
+ build_dir = build
29
+ $(shell mkdir -p $(build_dir))
30
+
31
+ os := $(shell uname -s)
32
+
33
+ prism_path = $(shell bundle show prism)
34
+ prism_include = $(prism_path)/include
35
+ prism_build = $(prism_path)/build
36
+
37
+ prism_flags = -I$(prism_include)
38
+ prism_ldflags = $(prism_build)/libprism.a
39
+
40
+ # Enable strict warnings
41
+ warning_flags = -Wall -Wextra -Werror -pedantic
42
+
43
+ # Debug build (no optimizations, debug symbols)
44
+ debug_flags = -g -O0 -Wno-unused-parameter
45
+
46
+ # Production build (optimized)
47
+ production_flags = $(warning_flags) -O3 -march=native -flto
48
+
49
+ # Shared library flags (only for `.so`/`.dylib`/`.bundle`)
50
+ shared_library_flags = -fPIC
51
+
52
+ # Default build mode (change this as needed)
53
+ flags = $(warning_flags) $(debug_flags) $(prism_flags) -std=c99
54
+
55
+ # Separate test compilation flags
56
+ test_flags = $(debug_flags) $(prism_flags) -std=gnu99
57
+
58
+ # Shared library build (if needed)
59
+ shared_flags = $(production_flags) $(shared_library_flags) $(prism_flags)
60
+
61
+ ifeq ($(os),Linux)
62
+ test_cflags = $(test_flags) -I/usr/include/check
63
+ test_ldflags = -L/usr/lib/x86_64-linux-gnu -lcheck -lm -lsubunit $(prism_ldflags)
64
+ cc = clang-19
65
+ clang_format = clang-format-19
66
+ clang_tidy = clang-tidy-19
67
+ endif
68
+
69
+ ifeq ($(os),Darwin)
70
+ brew_prefix := $(shell brew --prefix check)
71
+ test_cflags = $(test_flags) -I$(brew_prefix)/include
72
+ test_ldflags = -L$(brew_prefix)/lib -lcheck -lm $(prism_ldflags)
73
+ llvm_path = $(shell brew --prefix llvm@19)
74
+ cc = $(llvm_path)/bin/clang
75
+ clang_format = $(llvm_path)/bin/clang-format
76
+ clang_tidy = $(llvm_path)/bin/clang-tidy
77
+ endif
78
+
79
+ all: prism $(exec) $(lib_name) $(static_lib_name) test wasm
80
+
81
+ $(exec): $(objects)
82
+ $(cc) $(objects) $(flags) $(ldflags) $(prism_ldflags) -o $(exec)
83
+
84
+ $(lib_name): $(objects)
85
+ $(cc) -shared $(objects) $(shared_flags) $(ldflags) $(prism_ldflags) -o $(lib_name)
86
+ # cp $(lib_name) $(ruby_extension)
87
+
88
+ $(static_lib_name): $(objects)
89
+ ar rcs $(static_lib_name) $(objects)
90
+
91
+ src/%.o: src/%.c
92
+ $(cc) -c $(flags) -fPIC $< -o $@
93
+
94
+ test/%.o: test/%.c
95
+ $(cc) -c $(test_cflags) $(test_flags) $(prism_flags) $< -o $@
96
+
97
+ test: $(test_objects) $(non_main_objects)
98
+ $(cc) $(test_objects) $(non_main_objects) $(test_cflags) $(test_ldflags) -o $(test_exec)
99
+
100
+ clean:
101
+ rm -f $(exec) $(test_exec) $(lib_name) $(shared_lib_name) $(ruby_extension)
102
+ rm -rf $(objects) $(test_objects) $(extension_objects) lib/herb/*.bundle tmp
103
+ rm -rf $(prism_path)
104
+
105
+ bundle_install:
106
+ bundle install
107
+
108
+ prism: bundle_install
109
+ cd $(prism_path) && ruby templates/template.rb && make static && cd -
110
+
111
+ format:
112
+ $(clang_format) -i $(project_and_extension_files)
113
+
114
+ lint:
115
+ $(clang_format) --dry-run --Werror $(project_and_extension_files)
116
+
117
+ tidy:
118
+ $(clang_tidy) $(project_files) -- $(flags)
119
+
120
+ wasm:
121
+ cd wasm && make
data/README.md CHANGED
@@ -1,171 +1,166 @@
1
- herb [![Build Status](https://travis-ci.org/frodsan/herb.svg)](https://travis-ci.org/frodsan/herb)
2
- ====
1
+ # 🌿 Herb
3
2
 
4
- Minimal template engine with default escaping.
3
+ #### HTML + ERB (HTML Embedded Ruby)
5
4
 
6
- Description
7
- -----------
5
+ Powerful and seamless HTML-aware ERB parsing.
8
6
 
9
- Herb is a fork of [Mote] that uses a [ERB]-like style syntax and auto-escape HTML special characters by default.
7
+ ## Contributing
10
8
 
11
- Installation
12
- ------------
9
+ This project builds the Herb program and its associated unit tests using a Makefile for automation. The Makefile provides several useful commands for compiling, running tests, and cleaning the project.
13
10
 
14
- Add this line to your application's Gemfile:
11
+ ### Requirements
15
12
 
16
- ```ruby
17
- gem "herb"
18
- ```
13
+ - [**Check**](https://libcheck.github.io/check/): For unit testing.
14
+ - [**Clang 19**](https://clang.llvm.org): The compiler used to build this project.
15
+ - [**Clang Format 19**](https://clang.llvm.org/docs/ClangFormat.html): For formatting the project.
16
+ - [**Clang Tidy 19**](https://clang.llvm.org/extra/clang-tidy/): For linting the project.
17
+ - [**Prism Ruby Parser v1.4.0**](https://github.com/ruby/prism/releases/tag/v1.4.0): We use Prism for Parsing the Ruby Source Code in the HTML+ERB files.
18
+ - [**Ruby**](https://www.ruby-lang.org/en/): We need Ruby as a dependency for `bundler`.
19
+ - [**Bundler**](https://bundler.io): We are using `bundler` to build [`prism`](https://github.com/ruby/prism) from source so we can build `herb` against it.
20
+ - [**Emscripten**](https://emscripten.org): For the WebAssembly build of `libherb` so it can be used in the browser using the [`@herb-tools/browser`](https://github.com/marcoroth/herb/blob/main/javascript/packages/browser) package.
21
+ - [**Doxygen**](https://www.doxygen.nl): For building the C-Reference documentation pages.
19
22
 
20
- And then execute:
23
+ ##### For Linux
21
24
 
25
+ ```bash
26
+ xargs sudo apt-get install < Aptfile
22
27
  ```
23
- $ bundle
28
+ or:
29
+
30
+ ```bash
31
+ sudo apt-get install check clang-19 clang-tidy-19 clang-format-19 emscripten doxygen
24
32
  ```
25
33
 
26
- Or install it yourself as:
34
+ ##### For macOS (using Homebrew)
27
35
 
36
+ ```bash
37
+ brew bundle
28
38
  ```
29
- $ gem install herb
39
+ or:
40
+
41
+ ```bash
42
+ brew install check llvm@19 emscripten doxygen
30
43
  ```
31
44
 
32
- Basic Usage
33
- -----------
45
+ ### Building
34
46
 
35
- This is a basic example:
47
+ #### Clone the Repo
36
48
 
37
- ```ruby
38
- require "herb"
49
+ Clone the Git Repository:
39
50
 
40
- template = Herb.parse("your template goes here!")
41
- template.call
42
- # => "your template goes here!"
51
+ ```
52
+ git clone https://github.com/marcoroth/herb && cd herb/
43
53
  ```
44
54
 
45
- Herb recognizes two tags to evaluate Ruby code: `<% %>`, and `<%= %>`. The difference between them is that while the `<% %>` tags only evaluate the code, the `<%= %>` tags also prints the result to the template.
55
+ #### Build Herb
46
56
 
47
- Imagine that your template looks like this:
57
+ We can now compile all source files in `src/` and generate the `herb` executable.
48
58
 
49
- ```erb
50
- <% # single line code %>
51
- <% gems = ["rack", "cuba", "herb"] %>
59
+ ```bash
60
+ make all
61
+ ```
52
62
 
53
- <%
54
- # multi-line code
55
- sorted = gems.sort
56
- %>
63
+ > [!NOTE]
64
+ For any consecutive builds you can just run `make`/`make all`.
57
65
 
58
- <ul>
59
- <% sorted.each do |name| %>
60
- <li><%= name %></li>
61
- <% end %>
62
- </ul>
63
- ```
66
+ ### Run
64
67
 
65
- The generated result will be like:
68
+ The `herb` executable exposes a few commands for interacting with `.html.erb` files:
66
69
 
67
- ```html
68
- <ul>
69
- <li>cuba</li>
70
- <li>herb</li>
71
- <li>rack</li>
72
- </ul>
73
70
  ```
71
+ ❯ ./herb
72
+ ./herb [command] [options]
74
73
 
75
- Parameters
76
- ----------
77
-
78
- The values passed to the template are available as local variables:
74
+ Herb 🌿 Powerful and seamless HTML-aware ERB parsing.
79
75
 
80
- ```ruby
81
- template = Herb.parse("Hello {{ name }}", [:name])
82
- template.call(name: "Ruby")
83
- # => Hello Ruby
76
+ ./herb lex [file] - Lex a file
77
+ ./herb lex_json [file] - Lex a file and return the result as json.
78
+ ./herb parse [file] - Parse a file
79
+ ./herb ruby [file] - Extract Ruby from a file
80
+ ./herb html [file] - Extract HTML from a file
81
+ ./herb prism [file] - Extract Ruby from a file and parse the Ruby source with Prism
84
82
  ```
85
83
 
86
- You can also use the `params` local variable to access the given parameters:
84
+ Running the executable shows a pretty-printed output for the respective command and the time it took to execute:
87
85
 
88
- ```ruby
89
- template = Herb.parse("Hello {{ params[:name] }}")
90
- template.call(name: "Ruby")
91
- # => Hello Ruby
92
86
  ```
87
+ ❯ ./herb lex examples/simple_erb.html.erb
93
88
 
94
- Auto-escaping
95
- -------------
96
-
97
- By default, Herb escapes HTML special characters to prevent [XSS][xss] attacks. You can start the expression with an exclamation mark to disable escaping for that expression:
89
+ #<Herb::Token type="TOKEN_ERB_START" value="<%" range=[0, 2] start=(1:0) end=(1:2)>
90
+ #<Herb::Token type="TOKEN_ERB_CONTENT" value=" title " range=[2, 9] start=(1:2) end=(1:9)>
91
+ #<Herb::Token type="TOKEN_ERB_END" value="%>" range=[9, 11] start=(1:9) end=(1:11)>
92
+ #<Herb::Token type="TOKEN_NEWLINE" value="\n" range=[11, 12] start=(1:0) end=(2:1)>
93
+ #<Herb::Token type="TOKEN_EOF" value="" range=[12, 12] start=(2:1) end=(2:1)>
98
94
 
99
- ```ruby
100
- template = Herb.parse("Hello {{ name }}", [:name])
101
- template.call(name: "<b>World</b>")
102
- # => Hello &lt;b&gt;World&lt;b&gt;
95
+ Finished lexing in:
103
96
 
104
- template = Herb.parse("Hello {{! name }}", [:name])
105
- template.call(name: "<b>World</b>")
106
- # => Hello <b>World</b>
97
+ 12 µs
98
+ 0.012 ms
99
+ 0.000012 s
107
100
  ```
108
101
 
109
- Herb::Helpers
110
- --------------
102
+ ### Building the Ruby extension
111
103
 
112
- There's a helper available in the `Herb::Helpers` module, and you are
113
- free to include it in your code. To do it, just type:
104
+ We use `rake` and `rake-compiler` to compile the Ruby extension. Running rake will generate the needed templates, run make, build the needed artifacts, and run the Ruby tests.
114
105
 
115
- ```ruby
116
- include Herb::Helpers
106
+ ```bash
107
+ rake
117
108
  ```
118
109
 
119
- ### Using the `herb` helper
110
+ If `rake` was successful you can use `bundle console` to interact with `Herb`:
120
111
 
121
- The `herb` helper receives a file name and a hash and returns the rendered version of its content. The compiled template is cached for subsequent calls.
112
+ ```bash
113
+ bundle console
114
+ ```
122
115
 
123
- ```ruby
124
- herb("test/basic.erb", n: 3)
125
- # => "***\n"
126
116
  ```
117
+ irb(main):001> Herb.parse("<div></div>")
127
118
 
128
- ### Template caching
119
+ # => #<Herb::ParseResult:0x0000000 ... >
120
+ ```
129
121
 
130
- When the `herb` helper is first called with a template name, the file is read and parsed, and a proc is created and stored in the current thread. The parameters passed are defined as local variables in the template. If you want to provide more parameters once the template was cached, you won't be able to access the values as local variables, but you can always access the `params` hash.
122
+ ### Test
131
123
 
132
- For example:
124
+ Builds the test suite from files in `test/` and creates the `run_herb_tests` executable to run the tests:
133
125
 
134
- ```ruby
135
- # First call
136
- herb("foo.erb", a: 1, b: 2)
137
- ```
126
+ #### For the C Tests
138
127
 
139
- Contributing
140
- ------------
128
+ ```bash
129
+ make test && ./run_herb_tests
130
+ ```
141
131
 
142
- Fork the project with:
132
+ #### For the Ruby Tests
143
133
 
144
- ```
145
- $ git clone git@github.com:frodsan/herb.git
134
+ ```bash
135
+ rake test
146
136
  ```
147
137
 
148
- To install dependencies, use:
138
+ ### Clean
149
139
 
150
- ```
151
- $ bundle install
140
+ Removes the `herb`, `run_herb_tests`, `prism` installation, and all `.o` files.
141
+
142
+ ```bash
143
+ make clean
152
144
  ```
153
145
 
154
- To run the test suite, do:
146
+ ### Local Integration Testing
155
147
 
148
+ The `bin/integration` script allows for quick local iteration. On every run it cleans the directory, builds the source from scratch and runs all checks, including the C-Tests, Ruby Tests, Linters, and examples in succession.
149
+
150
+ ```bash
151
+ bin/integration
156
152
  ```
157
- $ rake test
153
+
154
+ The integration was successful if you see:
155
+
158
156
  ```
157
+ ❯ bin/integration
159
158
 
160
- For bug reports and pull requests use [GitHub][issues].
159
+ [...]
161
160
 
162
- License
163
- -------
161
+ Integration successful!
162
+ ```
164
163
 
165
- Herb is released under the [MIT License][mit].
164
+ ## License
166
165
 
167
- [erb]: http://ruby-doc.org/stdlib-2.3.1/libdoc/erb/rdoc/ERB.html
168
- [issues]: https://github.com/frodsan/herb/issues
169
- [mit]: http://www.opensource.org/licenses/MIT
170
- [mote]: https://github.com/soveran/mote
171
- [xss]: http://en.wikipedia.org/wiki/Cross-Site_Scripting
166
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.
data/Rakefile ADDED
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "English"
4
+ require "bundler/gem_tasks"
5
+ require "rake/testtask"
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.libs << "lib"
10
+ t.test_files = FileList["test/**/*_test.rb"]
11
+ end
12
+
13
+ task "make" do
14
+ puts "Running make..."
15
+ IO.popen("make") do |output|
16
+ output.each_line do |line|
17
+ puts line
18
+ end
19
+ end
20
+ end
21
+
22
+ begin
23
+ require "rake/extensiontask"
24
+
25
+ PLATFORMS = %w[
26
+ aarch64-linux-gnu
27
+ aarch64-linux-musl
28
+ arm-linux-gnu
29
+ arm-linux-musl
30
+ arm64-darwin
31
+ x86_64-darwin
32
+ x86_64-linux-gnu
33
+ x86_64-linux-musl
34
+ x86-linux-gnu
35
+ x86-linux-musl
36
+ ].freeze
37
+
38
+ exttask = Rake::ExtensionTask.new do |ext|
39
+ ext.name = "herb"
40
+ ext.source_pattern = "*.{c,h}"
41
+ ext.ext_dir = "ext/herb"
42
+ ext.lib_dir = "lib/herb"
43
+ ext.gem_spec = Gem::Specification.load("herb.gemspec")
44
+ ext.cross_compile = true
45
+ ext.cross_platform = PLATFORMS
46
+ end
47
+
48
+ Rake::Task[:compile].enhance do
49
+ raise "src/* could not be compiled #{$CHILD_STATUS.exitstatus}" if $CHILD_STATUS.exitstatus != 0
50
+ end
51
+
52
+ Rake::Task[:clean].enhance do
53
+ IO.popen("make clean") do |output|
54
+ output.each_line do |line|
55
+ puts line
56
+ end
57
+ end
58
+ end
59
+
60
+ task "gem:native" do
61
+ require "rake_compiler_dock"
62
+ # sh "bundle config set cache_all true"
63
+
64
+ PLATFORMS.each do |platform|
65
+ RakeCompilerDock.sh "bundle && rake native:#{platform} gem", platform: platform
66
+ end
67
+
68
+ RakeCompilerDock.sh "bundle && rake java gem", rubyvm: :jruby
69
+ rescue LoadError
70
+ abort "rake_compiler_dock is required to build native gems"
71
+ end
72
+
73
+ namespace "gem" do
74
+ task "prepare" do
75
+ require "rake_compiler_dock"
76
+ require "io/console"
77
+
78
+ # sh "bundle config set cache_all true"
79
+ sh "cp ~/.gem/gem-*.pem build/gem/ || true"
80
+
81
+ gemspec_path = File.expand_path("./herb.gemspec", __dir__)
82
+ spec = eval(File.read(gemspec_path), binding, gemspec_path)
83
+
84
+ RakeCompilerDock.set_ruby_cc_version(spec.required_ruby_version.as_list)
85
+
86
+ # ENV["GEM_PRIVATE_KEY_PASSPHRASE"] = STDIN.getpass("Enter passphrase of gem signature key: ")
87
+ rescue LoadError
88
+ abort "rake_compiler_dock is required for this task"
89
+ end
90
+
91
+ exttask.cross_platform.each do |platform|
92
+ desc "Build all native binary gems in parallel"
93
+ multitask "native" => platform
94
+
95
+ desc "Build the native gem for #{platform}"
96
+ task platform => "prepare" do
97
+ RakeCompilerDock.sh(
98
+ "bundle && rake native:#{platform} gem RUBY_CC_VERSION='#{ENV.fetch("RUBY_CC_VERSION", nil)}'",
99
+ platform: platform
100
+ )
101
+ end
102
+ end
103
+ end
104
+ rescue LoadError => e
105
+ desc "Compile task not available (rake-compiler not installed)"
106
+ task :compile do
107
+ puts e
108
+ abort <<~MESSAGE
109
+
110
+ "rake-compiler is required for this task.
111
+
112
+ Are you running `rake` using `bundle exec rake`?
113
+
114
+ Otherwise
115
+ * try to run bundle install
116
+ * add it to your Gemfile
117
+ * or install it with: gem install rake-compiler
118
+ MESSAGE
119
+ end
120
+ end
121
+
122
+ desc "Render out template files"
123
+ task :templates do
124
+ require_relative "templates/template"
125
+
126
+ Dir.glob("#{__dir__}/templates/**/*.erb").each do |template|
127
+ Herb::Template.render(template)
128
+ end
129
+ end
130
+
131
+ namespace :templates do
132
+ desc "Watch template files and regenerate on changes"
133
+ task :watch do
134
+ require "listen"
135
+
136
+ Rake::Task[:templates].execute
137
+
138
+ puts
139
+ puts "Watching config.yml and templates/**/*.erb for changes..."
140
+
141
+ ignore = Dir.glob("*/").map { |dir| Regexp.escape(dir.chomp("/")) }.map { |dir| %r{^#{dir}/} }
142
+
143
+ config_listener = Listen.to(".", only: /config\.yml$/, ignore: ignore) do
144
+ puts
145
+ puts "#{Time.now.strftime("[%Y-%m-%d %H:%M:%S]")} config.yml changed, regenerating all templates ..."
146
+ puts
147
+
148
+ Rake::Task[:templates].execute
149
+ end
150
+
151
+ template_listener = Listen.to("templates", only: /\.erb$/) do |modified, added, removed|
152
+ puts
153
+ (added + modified).each do |template|
154
+ template_file = template.delete_prefix("#{__dir__}/")
155
+
156
+ puts "#{Time.now.strftime("[%Y-%m-%d %H:%M:%S]")} Detected change, regenerating #{template_file} ..."
157
+ Herb::Template.render(template_file)
158
+ end
159
+
160
+ removed.each do |template|
161
+ puts
162
+ puts "#{template} was removed. Make sure to also remove the generated file."
163
+ end
164
+ end
165
+
166
+ config_listener.start
167
+ template_listener.start
168
+
169
+ sleep
170
+ rescue LoadError
171
+ abort "listen gem is required for this task. Add it to your Gemfile or install it with: gem install listen"
172
+ end
173
+ end
174
+
175
+ namespace :parse do
176
+ desc "Parse ERB files in a project directory"
177
+ task :project, [:path, :output_file] do |_t, args|
178
+ require_relative "lib/herb"
179
+
180
+ Herb::Project.new(args[:path], output_file: args[:output_file]).parse!
181
+ end
182
+ end
183
+
184
+ task default: [:templates, :make, :compile, :test]
data/exe/herb ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/herb"
5
+ Herb::CLI.new(ARGV).call