marked-conductor 1.0.27 → 1.0.28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.irbrc +2 -2
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -4
- data/bin/conductor +8 -98
- data/lib/conductor/array.rb +36 -2
- data/lib/conductor/boolean.rb +10 -0
- data/lib/conductor/command.rb +25 -1
- data/lib/conductor/condition.rb +41 -16
- data/lib/conductor/config.rb +37 -8
- data/lib/conductor/env.rb +3 -3
- data/lib/conductor/filter.rb +341 -196
- data/lib/conductor/hash.rb +15 -0
- data/lib/conductor/script.rb +2 -2
- data/lib/conductor/string.rb +51 -8
- data/lib/conductor/version.rb +1 -1
- data/lib/conductor/{yui-compressor.rb → yui_compressor.rb} +105 -85
- data/lib/conductor.rb +94 -2
- data/marked-conductor.gemspec +2 -1
- metadata +4 -4
data/lib/conductor/hash.rb
CHANGED
@@ -1,10 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Hash helpers
|
3
4
|
class ::Hash
|
5
|
+
##
|
6
|
+
## Destructive version of #symbolize_keys
|
7
|
+
##
|
8
|
+
## @see #symbolize_keys
|
9
|
+
##
|
10
|
+
## @return [Hash] hash with keys as symbols
|
11
|
+
##
|
4
12
|
def symbolize_keys!
|
5
13
|
replace symbolize_keys
|
6
14
|
end
|
7
15
|
|
16
|
+
##
|
17
|
+
## Convert all keys in hash to symbols. Works on nested hashes
|
18
|
+
##
|
19
|
+
## @see #symbolize_keys!
|
20
|
+
##
|
21
|
+
## @return [Hash] hash with keys as symbols
|
22
|
+
##
|
8
23
|
def symbolize_keys
|
9
24
|
each_with_object({}) { |(k, v), hsh| hsh[k.to_sym] = (v.is_a?(Hash) || v.is_a?(Array)) ? v.symbolize_keys : v }
|
10
25
|
end
|
data/lib/conductor/script.rb
CHANGED
@@ -22,7 +22,7 @@ module Conductor
|
|
22
22
|
## @param path The path
|
23
23
|
##
|
24
24
|
def path=(path)
|
25
|
-
@path = if %r{^[
|
25
|
+
@path = if %r{^[~/.]}.match?(path)
|
26
26
|
File.expand_path(path)
|
27
27
|
else
|
28
28
|
script_dir = File.expand_path("~/.config/conductor/scripts")
|
@@ -56,7 +56,7 @@ module Conductor
|
|
56
56
|
## @return [String] script results (STDOUT)
|
57
57
|
##
|
58
58
|
def run
|
59
|
-
stdin = Conductor.stdin
|
59
|
+
stdin = Conductor.stdin unless /\$\{?file\}?/.match?(args)
|
60
60
|
|
61
61
|
raise "Script path not defined" unless @path
|
62
62
|
|
data/lib/conductor/string.rb
CHANGED
@@ -15,6 +15,11 @@ class ::String
|
|
15
15
|
split(/,/).map { |s| Shellwords.shellsplit(s) }
|
16
16
|
end
|
17
17
|
|
18
|
+
##
|
19
|
+
## Normalize positional string to symbol
|
20
|
+
##
|
21
|
+
## @return [Symbol] position symbol (:start, :h1, :h2, :end)
|
22
|
+
##
|
18
23
|
def normalize_position
|
19
24
|
case self
|
20
25
|
when /^(be|s|t)/
|
@@ -28,6 +33,11 @@ class ::String
|
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
36
|
+
##
|
37
|
+
## Normalize a file include string to symbol
|
38
|
+
##
|
39
|
+
## @return [Symbol] include type symbol (:code, :raw, :file)
|
40
|
+
##
|
31
41
|
def normalize_include_type
|
32
42
|
case self
|
33
43
|
when /^c/
|
@@ -61,7 +71,7 @@ class ::String
|
|
61
71
|
## @return [Boolean] test result
|
62
72
|
##
|
63
73
|
def date?
|
64
|
-
dup.force_encoding("utf-8")
|
74
|
+
dup.force_encoding("utf-8") =~ /^\d{4}-\d{2}-\d{2}( \d{1,2}(:\d\d)? *([ap]m)?)?$/ ? true : false
|
65
75
|
end
|
66
76
|
|
67
77
|
##
|
@@ -70,7 +80,7 @@ class ::String
|
|
70
80
|
## @return [Boolean] test result
|
71
81
|
##
|
72
82
|
def time?
|
73
|
-
dup.force_encoding("utf-8")
|
83
|
+
dup.force_encoding("utf-8") =~ / \d{1,2}(:\d\d)? *([ap]m)?/i ? true : false
|
74
84
|
end
|
75
85
|
|
76
86
|
##
|
@@ -92,6 +102,11 @@ class ::String
|
|
92
102
|
dup.force_encoding("utf-8").sub(/ \d{1,2}(:\d\d)? *([ap]m)?/i, "")
|
93
103
|
end
|
94
104
|
|
105
|
+
##
|
106
|
+
## Round a date string to a day
|
107
|
+
##
|
108
|
+
## @param time [Symbol] :start or :end
|
109
|
+
##
|
95
110
|
def to_day(time = :end)
|
96
111
|
t = time == :end ? "23:59" : "00:00"
|
97
112
|
Chronic.parse("#{strip_time} #{t}")
|
@@ -134,13 +149,12 @@ class ::String
|
|
134
149
|
end
|
135
150
|
|
136
151
|
##
|
137
|
-
##
|
152
|
+
## Test if a string starts with Pandoc metadata
|
138
153
|
##
|
154
|
+
## @return [Boolean] test result
|
139
155
|
##
|
140
|
-
|
141
|
-
|
142
|
-
def to_bool!
|
143
|
-
replace to_bool
|
156
|
+
def pandoc?
|
157
|
+
dup.force_encoding('utf-8').match?(/^% \S/m)
|
144
158
|
end
|
145
159
|
|
146
160
|
##
|
@@ -149,11 +163,40 @@ class ::String
|
|
149
163
|
## @return [Boolean] Bool representation of the object.
|
150
164
|
##
|
151
165
|
def to_bool
|
152
|
-
case self.force_encoding('utf-8')
|
166
|
+
case self.dup.force_encoding('utf-8')
|
153
167
|
when /^[yt]/i
|
154
168
|
true
|
155
169
|
else
|
156
170
|
false
|
157
171
|
end
|
158
172
|
end
|
173
|
+
|
174
|
+
##
|
175
|
+
## Convert a string to a regular expression
|
176
|
+
##
|
177
|
+
## If the string matches /xxx/, it will be interpreted
|
178
|
+
## directly as a regex. Otherwise it will be escaped and
|
179
|
+
## converted to regex.
|
180
|
+
##
|
181
|
+
## @return [Regexp] Regexp representation of the string.
|
182
|
+
##
|
183
|
+
def to_rx
|
184
|
+
if self =~ %r{^/(.*?)/([im]+)?$}
|
185
|
+
m = Regexp.last_match
|
186
|
+
regex = m[1]
|
187
|
+
flags = m[2]
|
188
|
+
Regexp.new(regex, flags)
|
189
|
+
else
|
190
|
+
Regexp.new(Regexp.escape(self))
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
## Convert a string containing $1, $2 to a Regexp replace pattern
|
196
|
+
##
|
197
|
+
## @return [String] Pattern representation of the object.
|
198
|
+
##
|
199
|
+
def to_pattern
|
200
|
+
gsub(/\$(\d+)/, '\\\\\1').gsub(/(^["']|["']$)/, "")
|
201
|
+
end
|
159
202
|
end
|
data/lib/conductor/version.rb
CHANGED
@@ -1,42 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
1
3
|
# This is a Ruby port of the YUI CSS compressor
|
2
4
|
# See LICENSE for license information
|
3
5
|
|
4
6
|
module YuiCompressor
|
5
7
|
# Compress CSS rules using a variety of techniques
|
6
|
-
|
7
8
|
class Yui
|
8
9
|
attr_reader :input_size, :output_size
|
9
10
|
|
11
|
+
##
|
12
|
+
## Instantiate compressor
|
13
|
+
##
|
14
|
+
## @return [Yui] self
|
15
|
+
##
|
10
16
|
def initialize
|
11
|
-
@
|
17
|
+
@preserved_tokens = []
|
12
18
|
@comments = []
|
13
19
|
@input_size = 0
|
14
20
|
@output_size = 0
|
15
21
|
end
|
16
22
|
|
23
|
+
##
|
24
|
+
## YUI Compress string
|
25
|
+
##
|
26
|
+
## @param css [String] The css
|
27
|
+
## @param line_length [Integer] The line length
|
28
|
+
##
|
17
29
|
def compress(css, line_length = 0)
|
18
30
|
@input_size = css.length
|
19
31
|
|
20
32
|
css = process_comments_and_strings(css)
|
21
33
|
|
22
34
|
# Normalize all whitespace strings to single spaces. Easier to work with that way.
|
23
|
-
css.gsub!(/\s+/,
|
35
|
+
css.gsub!(/\s+/, " ")
|
24
36
|
|
25
37
|
# Remove the spaces before the things that should not have spaces before them.
|
26
38
|
# But, be careful not to turn "p :link {...}" into "p:link{...}"
|
27
39
|
# Swap out any pseudo-class colons with the token, and then swap back.
|
28
40
|
css.gsub!(/(?:^|\})[^{:]+\s+:+[^{]*\{/) do |match|
|
29
|
-
match.gsub(
|
41
|
+
match.gsub(":", "___PSEUDOCLASSCOLON___")
|
30
42
|
end
|
31
43
|
css.gsub!(/\s+([!{};:>+()\],])/, '\1')
|
32
44
|
css.gsub!(/([!{}:;>+(\[,])\s+/, '\1')
|
33
|
-
css.gsub!(
|
45
|
+
css.gsub!("___PSEUDOCLASSCOLON___", ":")
|
34
46
|
|
35
47
|
# special case for IE
|
36
48
|
css.gsub!(/:first-(line|letter)(\{|,)/, ':first-\1 \2')
|
37
49
|
|
38
50
|
# no space after the end of a preserved comment
|
39
|
-
css.gsub!(%r{\*/ },
|
51
|
+
css.gsub!(%r{\*/ }, "*/")
|
40
52
|
|
41
53
|
# If there is a @charset, then only allow one, and push to the top of the file.
|
42
54
|
css.gsub!(/^(.*)(@charset "[^"]*";)/i, '\2\1')
|
@@ -44,10 +56,10 @@ module YuiCompressor
|
|
44
56
|
|
45
57
|
# Put the space back in some cases, to support stuff like
|
46
58
|
# @media screen and (-webkit-min-device-pixel-ratio:0){
|
47
|
-
css.gsub!(/\band\(/i,
|
59
|
+
css.gsub!(/\band\(/i, "and (")
|
48
60
|
|
49
61
|
# remove unnecessary semicolons
|
50
|
-
css.gsub!(/;+\}/,
|
62
|
+
css.gsub!(/;+\}/, "}")
|
51
63
|
|
52
64
|
# Replace 0(%, em, ex, px, in, cm, mm, pt, pc) with just 0.
|
53
65
|
css.gsub!(/([\s:])([+-]?0)(?:%|em|ex|px|in|cm|mm|pt|pc)/i, '\1\2')
|
@@ -56,8 +68,9 @@ module YuiCompressor
|
|
56
68
|
css.gsub!(/:(?:0 )+0(;|\})/, ':0\1')
|
57
69
|
|
58
70
|
# Restore background-position:0 0; if required
|
59
|
-
css.gsub!(/(background-position|
|
60
|
-
|
71
|
+
css.gsub!(/(background-position|(?:(?:webkit|moz|o|ms)-)?transform-origin):0(;|\})/i) do
|
72
|
+
"#{::Regexp.last_match(1).downcase}:0 0#{::Regexp.last_match(2)}"
|
73
|
+
end
|
61
74
|
|
62
75
|
# Replace 0.6 with .6, but only when preceded by : or a space.
|
63
76
|
css.gsub!(/(:|\s)0+\.(\d+)/, '\1.\2')
|
@@ -65,7 +78,7 @@ module YuiCompressor
|
|
65
78
|
# Shorten colors from rgb(51,102,153) to #336699
|
66
79
|
# This makes it more likely that it'll get further compressed in the next step.
|
67
80
|
css.gsub!(/rgb\s*\(\s*([0-9,\s]+)\s*\)/) do |_match|
|
68
|
-
|
81
|
+
"#".dup << ::Regexp.last_match(1).scan(/\d+/).map { |n| n.to_i.to_s(16).rjust(2, "0") }.join
|
69
82
|
end
|
70
83
|
|
71
84
|
# Shorten colors from #AABBCC to #ABC. Note that we want to make sure
|
@@ -77,34 +90,35 @@ module YuiCompressor
|
|
77
90
|
css.gsub!(/([^"'=\s])(\s?)\s*#([0-9a-f])\3([0-9a-f])\4([0-9a-f])\5/i, '\1\2#\3\4\5')
|
78
91
|
|
79
92
|
# border: none -> border:0
|
80
|
-
css.gsub!(/(border|border-top|
|
81
|
-
|
93
|
+
css.gsub!(/(border|border-(top|right|bottom)|outline|background):none(;|\})/i) do
|
94
|
+
"#{::Regexp.last_match(1).downcase}:0#{::Regexp.last_match(2)}"
|
95
|
+
end
|
82
96
|
|
83
97
|
# shorter opacity IE filter
|
84
|
-
css.gsub!(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i,
|
98
|
+
css.gsub!(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i, "alpha(opacity=")
|
85
99
|
|
86
100
|
# Remove empty rules.
|
87
|
-
css.gsub!(%r{[^\};\{/]+\{\}},
|
101
|
+
css.gsub!(%r{[^\};\{/]+\{\}}, "")
|
88
102
|
|
89
|
-
if line_length
|
103
|
+
if line_length.positive?
|
90
104
|
# Some source control tools don't like it when files containing lines longer
|
91
105
|
# than, say 8000 characters, are checked in. The linebreak option is used in
|
92
106
|
# that case to split long lines after a specific column.
|
93
|
-
|
94
|
-
|
107
|
+
start_index = 0
|
108
|
+
idx = 0
|
95
109
|
length = css.length
|
96
|
-
while
|
97
|
-
|
98
|
-
if css[
|
99
|
-
css = css.slice(0,
|
100
|
-
|
110
|
+
while idx < length
|
111
|
+
idx += 1
|
112
|
+
if css[idx - 1, 1] == "}" && idx - start_index > line_length
|
113
|
+
css = "#{css.slice(0, idx)}\n#{css.slice(idx, length)}"
|
114
|
+
start_index = idx
|
101
115
|
end
|
102
116
|
end
|
103
117
|
end
|
104
118
|
|
105
119
|
# Replace multiple semi-colons in a row by a single one
|
106
120
|
# See SF bug #1980989
|
107
|
-
css.gsub!(/;+/,
|
121
|
+
css.gsub!(/;+/, ";")
|
108
122
|
|
109
123
|
# restore preserved comments and strings
|
110
124
|
css = restore_preserved_comments_and_strings(css)
|
@@ -116,26 +130,28 @@ module YuiCompressor
|
|
116
130
|
css
|
117
131
|
end
|
118
132
|
|
133
|
+
##
|
134
|
+
## Replace comments and strings with placeholders
|
135
|
+
##
|
136
|
+
## @param css_text [String] The css text
|
137
|
+
##
|
138
|
+
## @return [String] css text with strings replaced
|
119
139
|
def process_comments_and_strings(css_text)
|
120
|
-
css = css_text.
|
140
|
+
css = css_text.dup.force_encoding("ISO-8859-1").encode("utf-8", replace: nil)
|
121
141
|
|
122
|
-
|
123
|
-
|
124
|
-
i = 0
|
125
|
-
max = 0
|
126
|
-
token = ''
|
142
|
+
start_index = 0
|
143
|
+
token = ""
|
127
144
|
totallen = css.length
|
128
|
-
placeholder =
|
145
|
+
placeholder = ""
|
129
146
|
|
130
147
|
# collect all comment blocks
|
131
|
-
while (
|
132
|
-
|
133
|
-
|
134
|
-
token = css.slice(
|
148
|
+
while (start_index = css.index(%r{/\*}, start_index))
|
149
|
+
end_index = css.index(%r{\*/}, start_index + 2)
|
150
|
+
end_index ||= totallen
|
151
|
+
token = css.slice(start_index + 2..end_index - 1)
|
135
152
|
@comments.push(token)
|
136
|
-
css =
|
137
|
-
|
138
|
-
startIndex += 2
|
153
|
+
css = "#{css.slice(0..start_index + 1)}___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{@comments.length - 1}___#{css.slice(end_index, totallen)}"
|
154
|
+
start_index += 2
|
139
155
|
end
|
140
156
|
|
141
157
|
# preserve strings so their content doesn't get accidentally minified
|
@@ -146,82 +162,86 @@ endIndex, totallen).to_s
|
|
146
162
|
# maybe the string contains a comment-like substring?
|
147
163
|
# one, maybe more? put'em back then
|
148
164
|
if string =~ /___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_/
|
149
|
-
@comments.each_index do |
|
150
|
-
string.gsub!(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{
|
165
|
+
@comments.each_index do |idx|
|
166
|
+
string.gsub!(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{idx}___/, @comments[idx])
|
151
167
|
end
|
152
168
|
end
|
153
169
|
|
154
170
|
# minify alpha opacity in filter strings
|
155
|
-
string.gsub!(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i,
|
156
|
-
@
|
171
|
+
string.gsub!(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i, "alpha(opacity=")
|
172
|
+
@preserved_tokens.push(string)
|
157
173
|
|
158
|
-
quote
|
174
|
+
"#{quote}___YUICSSMIN_PRESERVED_TOKEN_#{@preserved_tokens.length - 1}___#{quote}"
|
159
175
|
end
|
160
176
|
|
161
|
-
# used to jump one index in loop
|
162
|
-
ie5_hack = false
|
177
|
+
# # used to jump one index in loop
|
178
|
+
# ie5_hack = false
|
163
179
|
# strings are safe, now wrestle the comments
|
164
|
-
@comments.each_index do |
|
165
|
-
if ie5_hack
|
166
|
-
|
167
|
-
|
168
|
-
end
|
180
|
+
@comments.each_index do |idx|
|
181
|
+
# if ie5_hack
|
182
|
+
# ie5_hack = false
|
183
|
+
# next
|
184
|
+
# end
|
169
185
|
|
170
|
-
token = @comments[
|
171
|
-
placeholder =
|
186
|
+
token = @comments[idx]
|
187
|
+
placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{idx}___"
|
172
188
|
|
173
189
|
# ! in the first position of the comment means preserve
|
174
190
|
# so push to the preserved tokens keeping the !
|
175
|
-
if token[0, 1]
|
176
|
-
@
|
177
|
-
css.gsub!(/#{placeholder}/i,
|
191
|
+
if token[0, 1] == "!"
|
192
|
+
@preserved_tokens.push(token)
|
193
|
+
css.gsub!(/#{placeholder}/i, "___YUICSSMIN_PRESERVED_TOKEN_#{@preserved_tokens.length - 1}___")
|
178
194
|
next
|
179
195
|
end
|
180
196
|
|
181
|
-
# \ in the last position looks like hack for Mac/IE5
|
182
|
-
# shorten that to /*\*/ and the next one to /**/
|
183
|
-
if token[-1, 1]
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
193
|
-
|
194
|
-
# keep empty comments after child selectors (IE7 hack)
|
195
|
-
# e.g. html >/**/ body
|
196
|
-
if
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
197
|
+
# # \ in the last position looks like hack for Mac/IE5
|
198
|
+
# # shorten that to /*\*/ and the next one to /**/
|
199
|
+
# if token[-1, 1] == "\\"
|
200
|
+
# @preserved_tokens.push("\\")
|
201
|
+
# css.gsub!(/#{placeholder}/, "___YUICSSMIN_PRESERVED_TOKEN_#{@preserved_tokens.length - 1}___")
|
202
|
+
# # keep the next comment but remove its content
|
203
|
+
# @preserved_tokens.push("")
|
204
|
+
# css.gsub!(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{idx + 1}___/,
|
205
|
+
# "___YUICSSMIN_PRESERVED_TOKEN_#{@preserved_tokens.length - 1}___")
|
206
|
+
# ie5_hack = true
|
207
|
+
# next
|
208
|
+
# end
|
209
|
+
|
210
|
+
# # keep empty comments after child selectors (IE7 hack)
|
211
|
+
# # e.g. html >/**/ body
|
212
|
+
# if token.empty? && (start_index = css.index(/#{placeholder}/)) &&
|
213
|
+
# (start_index > 2) && (css[start_index - 3, 1] == ">")
|
214
|
+
# @preserved_tokens.push("")
|
215
|
+
# css.gsub!(/#{placeholder}/, "___YUICSSMIN_PRESERVED_TOKEN_#{@preserved_tokens.length - 1}___")
|
216
|
+
# end
|
204
217
|
|
205
218
|
# in all other cases kill the comment
|
206
|
-
css.gsub!(%r{/\*#{placeholder}\*/},
|
219
|
+
css.gsub!(%r{/\*#{placeholder}\*/}, "")
|
207
220
|
end
|
208
221
|
|
209
222
|
css
|
210
223
|
end
|
211
224
|
|
225
|
+
##
|
226
|
+
## Restore saved comments and strings
|
227
|
+
##
|
228
|
+
## @param clean_css [String] The processed css
|
229
|
+
##
|
230
|
+
## @return [String] restored CSS
|
231
|
+
##
|
212
232
|
def restore_preserved_comments_and_strings(clean_css)
|
213
233
|
css = clean_css.clone
|
214
234
|
css_length = css.length
|
215
|
-
@
|
235
|
+
@preserved_tokens.each_index do |idx|
|
216
236
|
# slice these back into place rather than regex, because
|
217
237
|
# complex nested strings cause the replacement to fail
|
218
|
-
placeholder = "___YUICSSMIN_PRESERVED_TOKEN_#{
|
219
|
-
|
220
|
-
next unless
|
238
|
+
placeholder = "___YUICSSMIN_PRESERVED_TOKEN_#{idx}___"
|
239
|
+
start_index = css.index(placeholder, 0)
|
240
|
+
next unless start_index # skip if nil
|
221
241
|
|
222
|
-
|
242
|
+
end_index = start_index + placeholder.length
|
223
243
|
|
224
|
-
css = css.slice(0..
|
244
|
+
css = css.slice(0..start_index - 1).to_s + @preserved_tokens[idx] + css.slice(end_index, css_length).to_s
|
225
245
|
end
|
226
246
|
|
227
247
|
css
|
data/lib/conductor.rb
CHANGED
@@ -19,16 +19,108 @@ require_relative "conductor/filter"
|
|
19
19
|
require_relative "conductor/script"
|
20
20
|
require_relative "conductor/command"
|
21
21
|
require_relative "conductor/condition"
|
22
|
-
require_relative "conductor/
|
22
|
+
require_relative "conductor/yui_compressor"
|
23
23
|
|
24
|
+
# Main Conductor module
|
24
25
|
module Conductor
|
25
26
|
class << self
|
26
27
|
attr_accessor :original_input
|
27
28
|
attr_writer :stdin
|
28
29
|
|
30
|
+
##
|
31
|
+
## Return STDIN value, reading from STDIN if needed
|
32
|
+
##
|
33
|
+
## @return [String] STDIN contents
|
34
|
+
##
|
29
35
|
def stdin
|
30
|
-
warn "input on STDIN required" unless $stdin.stat.size.positive? || $stdin.fcntl(Fcntl::F_GETFL, 0).zero?
|
36
|
+
warn "input on STDIN required" unless ENV["CONDUCTOR_TEST"] || $stdin.stat.size.positive? || $stdin.fcntl(Fcntl::F_GETFL, 0).zero?
|
31
37
|
@stdin ||= $stdin.read.force_encoding("utf-8")
|
32
38
|
end
|
39
|
+
|
40
|
+
##
|
41
|
+
## Execute commands/scripts in the track
|
42
|
+
##
|
43
|
+
## @param track The track
|
44
|
+
##
|
45
|
+
## @return Resulting STDOUT output
|
46
|
+
##
|
47
|
+
def execute_track(track)
|
48
|
+
if track[:sequence]
|
49
|
+
track[:sequence].each do |cmd|
|
50
|
+
if cmd[:script]
|
51
|
+
script = Script.new(cmd[:script])
|
52
|
+
|
53
|
+
res = script.run
|
54
|
+
elsif cmd[:command]
|
55
|
+
command = Command.new(cmd[:command])
|
56
|
+
|
57
|
+
res = command.run
|
58
|
+
elsif cmd[:filter]
|
59
|
+
filter = Filter.new(cmd[:filter])
|
60
|
+
|
61
|
+
res = filter.process
|
62
|
+
end
|
63
|
+
|
64
|
+
Conductor.stdin = res unless res.nil?
|
65
|
+
end
|
66
|
+
elsif track[:script]
|
67
|
+
script = Script.new(track[:script])
|
68
|
+
|
69
|
+
Conductor.stdin = script.run
|
70
|
+
elsif track[:command]
|
71
|
+
command = Command.new(track[:command])
|
72
|
+
|
73
|
+
Conductor.stdin = command.run
|
74
|
+
elsif track[:filter]
|
75
|
+
filter = Filter.new(track[:filter])
|
76
|
+
|
77
|
+
Conductor.stdin = filter.process
|
78
|
+
end
|
79
|
+
|
80
|
+
Conductor.stdin
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
## Main function to parse conditions and
|
85
|
+
## execute actions. Executes recursively for
|
86
|
+
## sub-tracks.
|
87
|
+
##
|
88
|
+
## @param tracks The tracks to process
|
89
|
+
## @param res The current result
|
90
|
+
## @param condition The current condition
|
91
|
+
##
|
92
|
+
## @return [Array] result, matched condition(s)
|
93
|
+
##
|
94
|
+
def conduct(tracks, res = nil, condition = nil)
|
95
|
+
tracks.each do |track|
|
96
|
+
cond = Condition.new(track[:condition])
|
97
|
+
|
98
|
+
next unless cond.true?
|
99
|
+
|
100
|
+
# Build "matched condition" message
|
101
|
+
title = track[:title] || track[:condition]
|
102
|
+
condition ||= [""]
|
103
|
+
condition << title
|
104
|
+
condition.push(track.key?(:continue) ? " -> " : ", ")
|
105
|
+
|
106
|
+
res = execute_track(track)
|
107
|
+
|
108
|
+
if track[:tracks]
|
109
|
+
ts = track[:tracks]
|
110
|
+
|
111
|
+
res, condition = conduct(ts, res, condition)
|
112
|
+
|
113
|
+
next if res.nil?
|
114
|
+
end
|
115
|
+
|
116
|
+
break unless track[:continue]
|
117
|
+
end
|
118
|
+
|
119
|
+
if res&.strip == Conductor.original_input.strip
|
120
|
+
[nil, "No change in output"]
|
121
|
+
else
|
122
|
+
[res, condition]
|
123
|
+
end
|
124
|
+
end
|
33
125
|
end
|
34
126
|
end
|
data/marked-conductor.gemspec
CHANGED
@@ -9,7 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.email = ["me@brettterpstra.com"]
|
10
10
|
|
11
11
|
spec.summary = "A custom processor manager for Marked 2 (Mac)"
|
12
|
-
spec.description = "Conductor allows easy configuration of multiple scripts
|
12
|
+
spec.description = "Conductor allows easy configuration of multiple scripts" \
|
13
|
+
"which are run as custom pre/processors for Marked based on conditional statements."
|
13
14
|
spec.homepage = "https://github.com/ttscoff/marked-conductor"
|
14
15
|
spec.license = "MIT"
|
15
16
|
spec.required_ruby_version = ">= 2.6.0"
|
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.28
|
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-07-
|
11
|
+
date: 2024-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -184,7 +184,7 @@ dependencies:
|
|
184
184
|
- - "~>"
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: 0.5.0
|
187
|
-
description: Conductor allows easy configuration of multiple
|
187
|
+
description: Conductor allows easy configuration of multiple scriptswhich are run
|
188
188
|
as custom pre/processors for Marked based on conditional statements.
|
189
189
|
email:
|
190
190
|
- me@brettterpstra.com
|
@@ -218,7 +218,7 @@ files:
|
|
218
218
|
- lib/conductor/script.rb
|
219
219
|
- lib/conductor/string.rb
|
220
220
|
- lib/conductor/version.rb
|
221
|
-
- lib/conductor/
|
221
|
+
- lib/conductor/yui_compressor.rb
|
222
222
|
- marked-conductor.gemspec
|
223
223
|
- src/_README.md
|
224
224
|
- test.sh
|