marked-conductor 1.0.5 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +1 -1
- data/README.md +11 -3
- data/bin/conductor +20 -0
- data/lib/conductor/command.rb +0 -1
- data/lib/conductor/condition.rb +69 -24
- data/lib/conductor/env.rb +2 -2
- data/lib/conductor/string.rb +8 -0
- data/lib/conductor/version.rb +1 -1
- data/lib/conductor.rb +3 -1
- data/src/_README.md +11 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b5faacd380f833b615f2f848ed6f0bcb54dd955082b71228ab4f49c9e2bf0ac
|
4
|
+
data.tar.gz: 7c513f2fc4f75094e99ea27c48cf545ca738abe366271ec3da216f92ff0a4a5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c84b488b4cc93effd14039e59be3ea76ce4d8e0c5ab882ceb542e93d158fb82d11b5f46bfcd60d5942a265d6554107fa964bb8acafe2d9ced9e8302ea7eb10a6
|
7
|
+
data.tar.gz: 7e80a80708878d3ab4dbc515d5554c77af6bdd42b8ceb496c2b16bb48b054ea8696aa57351eeae0a35adb3de00ef2dce6c509e77c850aa8ebb4a71c2d672a4f2
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
### 1.0.7
|
2
|
+
|
3
|
+
2024-04-26 11:53
|
4
|
+
|
5
|
+
#### NEW
|
6
|
+
|
7
|
+
- Added test for MMD metadata, either for presence of meta or for specific keys or key values
|
8
|
+
|
9
|
+
#### FIXED
|
10
|
+
|
11
|
+
- Remove some debugging garbage
|
12
|
+
|
13
|
+
### 1.0.6
|
14
|
+
|
15
|
+
2024-04-26 11:17
|
16
|
+
|
17
|
+
#### FIXED
|
18
|
+
|
19
|
+
- Always wait for STDIN or Marked will crash. Still possible to use $file in script/command values
|
20
|
+
- More string encoding fixes
|
21
|
+
- "path contains" was returning $PATH instead of the filepath
|
22
|
+
|
1
23
|
### 1.0.5
|
2
24
|
|
3
25
|
2024-04-25 17:00
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -38,7 +38,7 @@ The top level key in the YAML file is `tracks:`. This is an array of hashes, eac
|
|
38
38
|
|
39
39
|
A simple config would look like:
|
40
40
|
|
41
|
-
```
|
41
|
+
```yaml
|
42
42
|
tracks:
|
43
43
|
- condition: yaml includes comments
|
44
44
|
script: blog-processor
|
@@ -52,7 +52,7 @@ Instead of a `script` or `command`, a track can contain another `tracks` key, in
|
|
52
52
|
|
53
53
|
For example, the following functions the same as `condition: phase is pre AND tree contains .obsidian AND (extension is md or extension is markdown)`:
|
54
54
|
|
55
|
-
```
|
55
|
+
```yaml
|
56
56
|
tracks:
|
57
57
|
- condition: phase is pre
|
58
58
|
tracks:
|
@@ -70,7 +70,7 @@ Available conditions are:
|
|
70
70
|
|
71
71
|
- `extension` (or `ext`): This will test the extension of the file, e.g. `ext is md` or `ext contains task`
|
72
72
|
- `tree contains ...`: This will test whether a given file or directory exists in any of the parent folders of the current file, starting with the current directory of the file. Example: `tree contains .obsidian` would test whether there was an `.obsidian` directory in any of the directories above the file (indicating it's within an Obsidian vault)
|
73
|
-
- `path`: This tests just the path itself, allowing conditions like `path contains _drafts` or `path does not contain _posts`.
|
73
|
+
- `path`: This tests just the path to the file itself, allowing conditions like `path contains _drafts` or `path does not contain _posts`.
|
74
74
|
- `phase`: Tests whether Marked is in Preprocessor or Processor phase, allowing conditions like `phase is preprocess` or `phase is process` (which can be shortened to `pre` and `pro`).
|
75
75
|
- `text`: This tests for any string match within the text of the document being processed. This can be used with operators `starts with`, `ends with`, or `contains`, e.g. `text contains @taskpaper` or `text does not contain <!--more-->`.
|
76
76
|
- If the test value is surrounded by forward slashes, it will be treated as a regular expression. Regexes are always flagged as case insensitive. Use it like `text contains /@\w+/`.
|
@@ -82,6 +82,7 @@ Available conditions are:
|
|
82
82
|
- If the YAML key is a date, it can be tested against with `before`, `after`, and `is`, and the value can be a natural language date, e.g. `yaml:date is after may 3, 2024`
|
83
83
|
- If both the YAML key value and the test value are numbers, you can use operators `greater than` (`>`), `less than` (`<`), `equal`/`is` (`=`/`==`), and `is not equal`/`not equals` (`!=`/`!==`). Numbers will be interpreted as floats.
|
84
84
|
- If the YAML value is a boolean, you can test with `is true` or `is not true` (or `is false`)
|
85
|
+
- `mmd` or `meta` will test for MultiMarkdown metadata using the same formatting as `yaml`.
|
85
86
|
- The following keywords act as a catchall and can be used as the last track in the config to act on any documents that aren't matched by preceding rules:
|
86
87
|
- `any`
|
87
88
|
- `else`
|
@@ -114,6 +115,13 @@ All of the [capabilities and requirements](https://marked2app.com/help/Custom_Pr
|
|
114
115
|
|
115
116
|
A script run by Conductor already knows it has the right type of file with the expected data and path, so your script can focus on just processing one file type. It's recommended to separate all of that logic you may already have written out into separate scripts and let Conductor handle the forking based on various criteria.
|
116
117
|
|
118
|
+
## Tips
|
119
|
+
|
120
|
+
- Config file must be valid YAML. Any value containing colons, brackets, or other special characters should be quoted, e.g. (`condition: "text contains my:text"`)
|
121
|
+
- You can see what condition matched in Marked by opening <b>Help->Show Custom Processor Log</b> and checking the STDERR output.
|
122
|
+
- To run [a custom processor for Bear](https://brettterpstra.com/2023/10/08/marked-and-bear/), use the condition `"text contains <!-- source: bear.app -->"`
|
123
|
+
- To run a custom processor for Obsidian, use the condition `tree contains .obsidian`
|
124
|
+
|
117
125
|
## Testing
|
118
126
|
|
119
127
|
In order to test from the command line, you'll need certain environment variables set. This can be done by exporting the following variables with your own definitions, or by running conductor with all of the variables preceding the command, e.g. `$ MARKED_ORIGIN=/path/to/markdown_file.md [...] conductor`.
|
data/bin/conductor
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative '../lib/conductor'
|
5
|
+
require 'optparse'
|
5
6
|
|
6
7
|
# raise 'No input on STDIN' unless Conductor.stdin
|
7
8
|
|
@@ -9,6 +10,8 @@ include Conductor
|
|
9
10
|
|
10
11
|
config = Config.new
|
11
12
|
|
13
|
+
stdin = Conductor.stdin
|
14
|
+
|
12
15
|
def conduct(tracks, res = nil, condition = nil)
|
13
16
|
tracks.each do |track|
|
14
17
|
cond = Condition.new(track[:condition])
|
@@ -41,6 +44,23 @@ def conduct(tracks, res = nil, condition = nil)
|
|
41
44
|
[res, condition]
|
42
45
|
end
|
43
46
|
|
47
|
+
options = {}
|
48
|
+
optparse = OptionParser.new do|opts|
|
49
|
+
opts.banner = "Called from Marked 2 as a Custom Pre/Processor"
|
50
|
+
|
51
|
+
opts.on('-v', '--version', 'Show version number') do
|
52
|
+
puts "conductor v#{Conductor::VERSION}"
|
53
|
+
Process.exit 0
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on('-h', '--help', 'Display this screen') do
|
57
|
+
puts opts
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
optparse.parse!
|
63
|
+
|
44
64
|
tracks = config.tracks
|
45
65
|
res, condition = conduct(tracks)
|
46
66
|
|
data/lib/conductor/command.rb
CHANGED
data/lib/conductor/condition.rb
CHANGED
@@ -150,7 +150,7 @@ module Conductor
|
|
150
150
|
end
|
151
151
|
|
152
152
|
def test_truthy(value1, value2, operator)
|
153
|
-
return false unless value2
|
153
|
+
return false unless value2&.bool?
|
154
154
|
|
155
155
|
value2 = value2.to_bool if value2.is_a?(String)
|
156
156
|
|
@@ -159,6 +159,59 @@ module Conductor
|
|
159
159
|
operator == :not_equal ? !res : res
|
160
160
|
end
|
161
161
|
|
162
|
+
def test_yaml(content, value, key, operator)
|
163
|
+
yaml = YAML.safe_load(content.split(/^(?:---|\.\.\.)/)[1])
|
164
|
+
|
165
|
+
return operator == :not_equal ? true : false unless yaml
|
166
|
+
|
167
|
+
if key
|
168
|
+
value1 = yaml[key]
|
169
|
+
return operator == :not_equal ? true : false if value1.nil?
|
170
|
+
|
171
|
+
value1 = value1.join(',') if value1.is_a?(Array)
|
172
|
+
if %i[type_of not_type_of].include?(operator)
|
173
|
+
test_type(value1, value, operator)
|
174
|
+
elsif value1.bool?
|
175
|
+
test_truthy(value1, value, operator)
|
176
|
+
elsif value1.number? && value2.number? && %i[gt lt equal not_equal].include?(operator)
|
177
|
+
test_operator(value1, value, operator)
|
178
|
+
else
|
179
|
+
test_string(value1, value, operator)
|
180
|
+
end
|
181
|
+
else
|
182
|
+
res = value ? yaml.key?(value) : true
|
183
|
+
operator == :not_equal ? !res : res
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_meta(content, value, key, operator)
|
188
|
+
headers = []
|
189
|
+
content.split(/\n/).each do |line|
|
190
|
+
break if line == /^ *\n$/ || line !~ /\w+: *\S/
|
191
|
+
|
192
|
+
headers << line
|
193
|
+
end
|
194
|
+
|
195
|
+
return operator == :not_equal if headers.empty?
|
196
|
+
|
197
|
+
return operator != :not_equal if value.nil?
|
198
|
+
|
199
|
+
meta = {}
|
200
|
+
headers.each do |h|
|
201
|
+
parts = h.split(/ *: */)
|
202
|
+
k = parts[0].strip.downcase.gsub(/ +/, '')
|
203
|
+
v = parts[1..].join(':').strip
|
204
|
+
meta[k] = v
|
205
|
+
end
|
206
|
+
|
207
|
+
if key
|
208
|
+
test_string(meta[key], value, operator)
|
209
|
+
else
|
210
|
+
res = value ? meta.key?(value) : true
|
211
|
+
operator == :not_equal ? !res : res
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
162
215
|
def test_condition(condition)
|
163
216
|
type, value, operator = split_condition(condition)
|
164
217
|
|
@@ -177,35 +230,27 @@ module Conductor
|
|
177
230
|
when /^tree/i
|
178
231
|
test_tree(@env[:origin], value, operator)
|
179
232
|
when /^(path|dir)/i
|
180
|
-
test_string(@env[:
|
233
|
+
test_string(@env[:filepath], value, operator) ? true : false
|
181
234
|
when /^phase/i
|
182
235
|
test_string(@env[:phase], value, :starts_with) ? true : false
|
183
236
|
when /^text/i
|
184
|
-
test_string(IO.read(@env[:filepath]), value, operator) ? true : false
|
237
|
+
test_string(IO.read(@env[:filepath]).force_encoding('utf-8'), value, operator) ? true : false
|
185
238
|
when /^(yaml|headers|frontmatter)(?::(.*?))?$/i
|
186
239
|
m = Regexp.last_match
|
240
|
+
|
241
|
+
key = m[2] || nil
|
242
|
+
|
187
243
|
content = IO.read(@env[:filepath]).force_encoding('utf-8')
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
elsif value1.bool?
|
199
|
-
test_truthy(value1, value, operator)
|
200
|
-
elsif value1.number? && value2.number? && %i[gt lt equal not_equal].include?(operator)
|
201
|
-
test_operator(value1, value, operator)
|
202
|
-
else
|
203
|
-
test_string(value1, value, operator)
|
204
|
-
end
|
205
|
-
else
|
206
|
-
res = value? ? yaml.key?(value) : true
|
207
|
-
operator == :not_equal ? !res : res
|
208
|
-
end
|
244
|
+
|
245
|
+
content.yaml? ? test_yaml(content, value, key, operator) : false
|
246
|
+
when /^(mmd|meta(?:data)?)(?::(.*?))?$/i
|
247
|
+
m = Regexp.last_match
|
248
|
+
|
249
|
+
key = m[2] || nil
|
250
|
+
|
251
|
+
content = IO.read(@env[:filepath]).force_encoding('utf-8')
|
252
|
+
|
253
|
+
content.meta? ? test_meta(content, value, key, operator) : false
|
209
254
|
else
|
210
255
|
false
|
211
256
|
end
|
data/lib/conductor/env.rb
CHANGED
@@ -28,8 +28,8 @@ module Conductor
|
|
28
28
|
css_path: '/Applications/Marked 2.app/Contents/Resources/swiss.css',
|
29
29
|
ext: 'md',
|
30
30
|
includes: [],
|
31
|
-
origin: '/Users/ttscoff/
|
32
|
-
filepath: '/Users/ttscoff/
|
31
|
+
origin: '/Users/ttscoff/Desktop/Code/marked-conductor/',
|
32
|
+
filepath: '/Users/ttscoff/Desktop/Code/marked-conductor/README.md',
|
33
33
|
phase: 'PREPROCESS',
|
34
34
|
outline: 'NONE',
|
35
35
|
path: '/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/ttscoff/Dropbox/Writing/brettterpstra.com/_drafts/'
|
data/lib/conductor/string.rb
CHANGED
@@ -42,6 +42,14 @@ class ::String
|
|
42
42
|
dup.force_encoding('utf-8').match(/^(?:y(?:es)?|no?|t(?:rue)?|f(?:alse)?)$/) ? true : false
|
43
43
|
end
|
44
44
|
|
45
|
+
def meta?
|
46
|
+
self =~ /^---/m
|
47
|
+
end
|
48
|
+
|
49
|
+
def yaml?
|
50
|
+
self =~ /^\w+: +\S+/m
|
51
|
+
end
|
52
|
+
|
45
53
|
def to_bool!
|
46
54
|
replace to_bool
|
47
55
|
end
|
data/lib/conductor/version.rb
CHANGED
data/lib/conductor.rb
CHANGED
@@ -7,6 +7,7 @@ require 'fcntl'
|
|
7
7
|
require 'time'
|
8
8
|
require 'chronic'
|
9
9
|
require 'fileutils'
|
10
|
+
require_relative 'conductor/version'
|
10
11
|
require_relative 'conductor/env'
|
11
12
|
require_relative 'conductor/config'
|
12
13
|
require_relative 'conductor/hash'
|
@@ -20,7 +21,8 @@ require_relative 'conductor/condition'
|
|
20
21
|
module Conductor
|
21
22
|
class << self
|
22
23
|
def stdin
|
23
|
-
|
24
|
+
warn 'input on STDIN required' unless $stdin.stat.size.positive? || $stdin.fcntl(Fcntl::F_GETFL, 0).zero?
|
25
|
+
@stdin ||= $stdin.read.strip.force_encoding('utf-8')
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
data/src/_README.md
CHANGED
@@ -38,7 +38,7 @@ The top level key in the YAML file is `tracks:`. This is an array of hashes, eac
|
|
38
38
|
|
39
39
|
A simple config would look like:
|
40
40
|
|
41
|
-
```
|
41
|
+
```yaml
|
42
42
|
tracks:
|
43
43
|
- condition: yaml includes comments
|
44
44
|
script: blog-processor
|
@@ -52,7 +52,7 @@ Instead of a `script` or `command`, a track can contain another `tracks` key, in
|
|
52
52
|
|
53
53
|
For example, the following functions the same as `condition: phase is pre AND tree contains .obsidian AND (extension is md or extension is markdown)`:
|
54
54
|
|
55
|
-
```
|
55
|
+
```yaml
|
56
56
|
tracks:
|
57
57
|
- condition: phase is pre
|
58
58
|
tracks:
|
@@ -70,7 +70,7 @@ Available conditions are:
|
|
70
70
|
|
71
71
|
- `extension` (or `ext`): This will test the extension of the file, e.g. `ext is md` or `ext contains task`
|
72
72
|
- `tree contains ...`: This will test whether a given file or directory exists in any of the parent folders of the current file, starting with the current directory of the file. Example: `tree contains .obsidian` would test whether there was an `.obsidian` directory in any of the directories above the file (indicating it's within an Obsidian vault)
|
73
|
-
- `path`: This tests just the path itself, allowing conditions like `path contains _drafts` or `path does not contain _posts`.
|
73
|
+
- `path`: This tests just the path to the file itself, allowing conditions like `path contains _drafts` or `path does not contain _posts`.
|
74
74
|
- `phase`: Tests whether Marked is in Preprocessor or Processor phase, allowing conditions like `phase is preprocess` or `phase is process` (which can be shortened to `pre` and `pro`).
|
75
75
|
- `text`: This tests for any string match within the text of the document being processed. This can be used with operators `starts with`, `ends with`, or `contains`, e.g. `text contains @taskpaper` or `text does not contain <!--more-->`.
|
76
76
|
- If the test value is surrounded by forward slashes, it will be treated as a regular expression. Regexes are always flagged as case insensitive. Use it like `text contains /@\w+/`.
|
@@ -82,6 +82,7 @@ Available conditions are:
|
|
82
82
|
- If the YAML key is a date, it can be tested against with `before`, `after`, and `is`, and the value can be a natural language date, e.g. `yaml:date is after may 3, 2024`
|
83
83
|
- If both the YAML key value and the test value are numbers, you can use operators `greater than` (`>`), `less than` (`<`), `equal`/`is` (`=`/`==`), and `is not equal`/`not equals` (`!=`/`!==`). Numbers will be interpreted as floats.
|
84
84
|
- If the YAML value is a boolean, you can test with `is true` or `is not true` (or `is false`)
|
85
|
+
- `mmd` or `meta` will test for MultiMarkdown metadata using the same formatting as `yaml`.
|
85
86
|
- The following keywords act as a catchall and can be used as the last track in the config to act on any documents that aren't matched by preceding rules:
|
86
87
|
- `any`
|
87
88
|
- `else`
|
@@ -114,6 +115,13 @@ All of the [capabilities and requirements](https://marked2app.com/help/Custom_Pr
|
|
114
115
|
|
115
116
|
A script run by Conductor already knows it has the right type of file with the expected data and path, so your script can focus on just processing one file type. It's recommended to separate all of that logic you may already have written out into separate scripts and let Conductor handle the forking based on various criteria.
|
116
117
|
|
118
|
+
## Tips
|
119
|
+
|
120
|
+
- Config file must be valid YAML. Any value containing colons, brackets, or other special characters should be quoted, e.g. (`condition: "text contains my:text"`)
|
121
|
+
- You can see what condition matched in Marked by opening <b>Help->Show Custom Processor Log</b> and checking the STDERR output.
|
122
|
+
- To run [a custom processor for Bear](https://brettterpstra.com/2023/10/08/marked-and-bear/), use the condition `"text contains <!-- source: bear.app -->"`
|
123
|
+
- To run a custom processor for Obsidian, use the condition `tree contains .obsidian`
|
124
|
+
|
117
125
|
## Testing
|
118
126
|
|
119
127
|
In order to test from the command line, you'll need certain environment variables set. This can be done by exporting the following variables with your own definitions, or by running conductor with all of the variables preceding the command, e.g. `$ MARKED_ORIGIN=/path/to/markdown_file.md [...] conductor`.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marked-conductor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|