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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c6a0da9f71e766f19edb6cb13fc27139af3934f3cdf013b0c51164cc3b20d73f
4
- data.tar.gz: a0d4c8b2d37653632d8757f0704008fbc370a6edcc89c46e9f1eac8927cab9e7
3
+ metadata.gz: 3b5faacd380f833b615f2f848ed6f0bcb54dd955082b71228ab4f49c9e2bf0ac
4
+ data.tar.gz: 7c513f2fc4f75094e99ea27c48cf545ca738abe366271ec3da216f92ff0a4a5e
5
5
  SHA512:
6
- metadata.gz: 5ccaa5df5811bf5433bea16f2ddc5b71c056592250b0757d83119e998a65426eaeb04e291f3b758bc0e74e64b1a6f58bcbcb59ed7a9eccdf5e58dfe26e474886
7
- data.tar.gz: 340f3e73ff68f7026f169cc6c686de8dcd6651836c6b685e886e5a3c115f17b676ea889565929a6ec778ad017b914c0c796ac4e8b724fc8808288535bf5da54d
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- marked-conductor (0.1.0)
4
+ marked-conductor (1.0.5)
5
5
  chronic (~> 0.10.2)
6
6
  tty-which (~> 0.5.0)
7
7
 
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
 
@@ -45,7 +45,6 @@ module Conductor
45
45
  if use_stdin
46
46
  `echo #{Shellwords.escape(stdin)} | #{Env} #{path} #{args}`
47
47
  else
48
- puts "#{Env} #{path} #{args}"
49
48
  `#{Env} #{path} #{args}`
50
49
  end
51
50
  end
@@ -150,7 +150,7 @@ module Conductor
150
150
  end
151
151
 
152
152
  def test_truthy(value1, value2, operator)
153
- return false unless value2.bool?
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[:origin], value, operator) ? true : false
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
- return false unless content =~ /^---/
189
-
190
- yaml = YAML.safe_load(content.split(/^(?:---|\.\.\.)/)[1])
191
-
192
- return false unless yaml
193
- if m[2]
194
- value1 = yaml[m[2]]
195
- value1 = value1.join(',') if value1.is_a?(Array)
196
- if %i[type_of not_type_of].include?(operator)
197
- test_type(value1, value, operator)
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/Dropbox/Writing/brettterpstra.com/_drafts/',
32
- filepath: '/Users/ttscoff/Dropbox/Writing/brettterpstra.com/_drafts/marked-2-and-obsidian.md',
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/'
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Conductor
4
- VERSION = '1.0.5'
4
+ VERSION = '1.0.7'
5
5
  end
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
- @stdin ||= $stdin.read.strip.force_encoding('utf-8') if $stdin.stat.size.positive? || $stdin.fcntl(Fcntl::F_GETFL, 0).zero?
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.5
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-25 00:00:00.000000000 Z
11
+ date: 2024-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry