howzit 2.1.26 → 2.1.28

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19fc185635709d53c4d7dcf0b437d4ec6b00cdd341d734e4655ef4e8e1dbfd3a
4
- data.tar.gz: 9305e6edf7a8c4f7bf6d2d6a4a1aed14313aac73b658595a877314e929c15c8b
3
+ metadata.gz: cd3edf8d90a9cf744655479a0d81d11453d30d4d32f1f43cd719b6133b7c18d1
4
+ data.tar.gz: d8c862edff83fb8a456057682bf5063ddd7dfca44e37e45a97faee14482a1fdd
5
5
  SHA512:
6
- metadata.gz: a35475dfaf7aa381157964466046ff8c94b0a4282bd9bbb8c067b7d344527d8ba95a296934ce935375111c4c255122cd3c684829d761b4962c517ea6dfadc14b
7
- data.tar.gz: 41ae72b53d9602fb9b6df8231a4d1db8d9f134b78460e2243e8afaf616528279d0e7b08d68820a330994935579186058838a5d5e5c288b809aa46d0670b71b0f
6
+ metadata.gz: '08ef313bfa86f22c700610a114bafbbcf6aa769667ada6c007dad65370fc90cefad1562df99227676bc4e70fdaf0c82d751a0ecb86321ef09f0955e8d5bc1c23'
7
+ data.tar.gz: 026b8782c3f889adbf18dd4841faa709fd460eed3710c1402c089f5926f50c0340b2b9ec471baaf268cf456256a7ee3de8ad35741bac7b57f2fe0f0a931d8442
data/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ ### 2.1.28
2
+
3
+ 2025-12-31 10:21
4
+
5
+ #### CHANGED
6
+
7
+ - Refactored code to use more concise unless statement syntax
8
+
9
+ #### NEW
10
+
11
+ - Added "token" matching mode for multi-word searches that matches words in order
12
+
13
+ #### IMPROVED
14
+
15
+ - Enhanced fuzzy matching to use token-based approach for multi-word searches
16
+ - Default partial matching now uses token-based matching for better multi-word search results
17
+
18
+ #### FIXED
19
+
20
+ - Improved error handling when topics are not found or invalid
21
+ - Fixed topic selection when using interactive choose mode with topics that have named arguments
22
+ - Added nil checks to prevent errors when arguments array is nil
23
+ - Improved handling of empty search terms to prevent matching all topics
24
+
25
+ ### 2.1.27
26
+
27
+ 2025-12-26 08:59
28
+
29
+ #### IMPROVED
30
+
31
+ - Task titles now support variable substitution using ${VAR} syntax, so titles like "@run(echo test) Title with ${var}" will replace ${var} with its value from topic metadata. This applies to all task types (run, copy, open, include) and code block titles.
32
+
33
+ #### FIXED
34
+
35
+ - Task and topic names containing dollar signs (like $text$ or ${VAR}) now display correctly in run report output without causing color code interpretation issues. Dollar signs are properly escaped during formatting and unescaped in the final output.
36
+
1
37
  ### 2.1.26
2
38
 
3
39
  2025-12-26 04:53
@@ -291,21 +291,17 @@ module Howzit
291
291
  title = File.basename(Dir.pwd)
292
292
  # prompt = TTY::Prompt.new
293
293
  if default
294
- input = title
294
+ title
295
295
  else
296
296
  title = Prompt.get_line('{bw}Project name{x}'.c, default: title)
297
297
  end
298
298
  summary = ''
299
- unless default
300
- summary = Prompt.get_line('{bw}Project summary{x}'.c)
301
- end
299
+ summary = Prompt.get_line('{bw}Project summary{x}'.c) unless default
302
300
 
303
301
  # Template selection
304
302
  selected_templates = []
305
303
  template_metadata = {}
306
- unless default
307
- selected_templates, template_metadata = select_templates_for_note(title)
308
- end
304
+ selected_templates, template_metadata = select_templates_for_note(title) unless default
309
305
 
310
306
  fname = 'buildnotes.md'
311
307
  unless default
@@ -314,9 +310,7 @@ module Howzit
314
310
 
315
311
  # Build metadata section
316
312
  metadata_lines = []
317
- unless selected_templates.empty?
318
- metadata_lines << "template: #{selected_templates.join(',')}"
319
- end
313
+ metadata_lines << "template: #{selected_templates.join(',')}" unless selected_templates.empty?
320
314
  template_metadata.each do |key, value|
321
315
  metadata_lines << "#{key}: #{value}"
322
316
  end
@@ -386,7 +380,7 @@ module Howzit
386
380
  ##
387
381
  ## @return [Array<Array, Hash>] Array of [selected_template_names, required_vars_hash]
388
382
  ##
389
- def select_templates_for_note(project_title)
383
+ def select_templates_for_note(_project_title)
390
384
  template_dir = Howzit.config.template_folder
391
385
  template_glob = File.join(template_dir, '*.md')
392
386
  template_files = Dir.glob(template_glob)
@@ -879,7 +873,21 @@ module Howzit
879
873
  ## single topic
880
874
  ##
881
875
  def process_topic(topic, run, single: false)
882
- new_topic = topic.is_a?(String) ? find_topic(topic)[0] : topic.dup
876
+ if topic.is_a?(String)
877
+ matches = find_topic(topic)
878
+ new_topic = matches.empty? ? nil : matches[0]
879
+ else
880
+ new_topic = begin
881
+ topic.dup
882
+ rescue StandardError
883
+ topic
884
+ end
885
+ end
886
+
887
+ if new_topic.nil?
888
+ Howzit.console.warn "{br}ERROR:{xr} Topic not found or invalid: {bw}#{topic.is_a?(String) ? topic : topic.inspect}{x}".c
889
+ return ''
890
+ end
883
891
 
884
892
  output = if run
885
893
  new_topic.run
@@ -946,13 +954,67 @@ module Howzit
946
954
  when :all
947
955
  topic_matches.concat(matches.sort_by(&:title))
948
956
  else
949
- topic_matches.concat(Prompt.choose(matches.map(&:title), height: :max, query: Howzit.options[:grep]))
957
+ selected_titles = Prompt.choose(matches.map(&:title), height: :max, query: Howzit.options[:grep])
958
+ # Convert selected titles back to topic objects
959
+ selected_titles.each do |title|
960
+ matched_topic = matches.find { |t| t.title == title }
961
+ topic_matches.push(matched_topic) if matched_topic
962
+ end
950
963
  end
964
+ topic_matches.compact! # Remove any nil values
951
965
  process_topic_matches(topic_matches, output)
952
966
  elsif Howzit.options[:choose]
953
967
  topic_matches = []
954
968
  titles = Prompt.choose(list_topics, height: :max)
955
- titles.each { |title| topic_matches.push(find_topic(title)[0]) }
969
+ titles.each do |selected_title|
970
+ selected_title = selected_title.strip
971
+ matched_topic = nil
972
+
973
+ # First, try to match by reconstructing the formatted title exactly as list_topics does
974
+ @topics.each do |topic|
975
+ formatted_title = topic.title.dup
976
+ formatted_title += "(#{topic.named_args.keys.join(', ')})" unless topic.named_args.empty?
977
+ formatted_title = formatted_title.strip
978
+
979
+ # Normalize both titles for comparison (remove extra whitespace, normalize case)
980
+ normalized_formatted = formatted_title.downcase.gsub(/\s+/, ' ')
981
+ normalized_selected = selected_title.downcase.gsub(/\s+/, ' ')
982
+
983
+ if formatted_title == selected_title || normalized_formatted == normalized_selected
984
+ matched_topic = topic
985
+ break
986
+ end
987
+ end
988
+
989
+ # If still not found, try matching by base title (without args)
990
+ unless matched_topic
991
+ clean_selected = selected_title.sub(/ *\([^)]*\) *$/, '').strip
992
+ matched_topic = @topics.find do |topic|
993
+ base_title = topic.title.strip
994
+ base_title.downcase == clean_selected.downcase || base_title == clean_selected
995
+ end
996
+ end
997
+
998
+ # Last resort: use find_topic with the cleaned title
999
+ unless matched_topic
1000
+ clean_selected = selected_title.sub(/ *\([^)]*\) *$/, '').strip
1001
+ matches = find_topic(clean_selected)
1002
+ matched_topic = matches[0] unless matches.empty?
1003
+ end
1004
+
1005
+ if matched_topic
1006
+ topic_matches.push(matched_topic)
1007
+ else
1008
+ Howzit.console.warn "{br}WARNING:{xr} Could not find topic matching: {bw}#{selected_title}{x}".c
1009
+ end
1010
+ end
1011
+
1012
+ topic_matches.compact! # Remove any nil values
1013
+ if topic_matches.empty?
1014
+ output.push(%({bR}ERROR:{xr} No valid topics found from selection{x}\n).c)
1015
+ Util.show(output.join("\n"), { color: true, highlight: false, paginate: false, wrap: 0 })
1016
+ Process.exit 1
1017
+ end
956
1018
  process_topic_matches(topic_matches, output)
957
1019
  elsif !Howzit.cli_args.empty?
958
1020
  # Check if first arg is "default"
@@ -964,23 +1026,21 @@ module Howzit
964
1026
  topic_matches = collect_topic_matches(search, output)
965
1027
  process_topic_matches(topic_matches, output)
966
1028
  end
967
- else
1029
+ elsif Howzit.options[:run]
968
1030
  # No arguments
969
- if Howzit.options[:run]
970
- # Check for default metadata when running with no args
971
- if @metadata.key?('default')
972
- process_default_metadata(output)
973
- else
974
- Howzit.run_log = []
975
- Howzit.multi_topic_run = topics.length > 1
976
- topics.each { |k| output.push(process_topic(k, false, single: false)) }
977
- finalize_output(output)
978
- end
1031
+ # Check for default metadata when running with no args
1032
+ if @metadata.key?('default')
1033
+ process_default_metadata(output)
979
1034
  else
980
- # Show all topics
1035
+ Howzit.run_log = []
1036
+ Howzit.multi_topic_run = topics.length > 1
981
1037
  topics.each { |k| output.push(process_topic(k, false, single: false)) }
982
1038
  finalize_output(output)
983
1039
  end
1040
+ else
1041
+ # Show all topics
1042
+ topics.each { |k| output.push(process_topic(k, false, single: false)) }
1043
+ finalize_output(output)
984
1044
  end
985
1045
  end
986
1046
 
@@ -996,7 +1056,12 @@ module Howzit
996
1056
  def collect_topic_matches(search_terms, output)
997
1057
  all_matches = []
998
1058
 
1059
+ # If no search terms, return empty (don't match all topics)
1060
+ return [] if search_terms.nil? || search_terms.empty?
1061
+
999
1062
  search_terms.each do |s|
1063
+ next if s.nil? || s.strip.empty?
1064
+
1000
1065
  # First check for exact whole-word matches
1001
1066
  exact_matches = find_topic_exact(s)
1002
1067
 
@@ -1024,7 +1089,7 @@ module Howzit
1024
1089
  ##
1025
1090
  ## @return [Array] Array of matched topics
1026
1091
  ##
1027
- def resolve_fuzzy_matches(search_term, output)
1092
+ def resolve_fuzzy_matches(search_term, _output)
1028
1093
  matches = find_topic(search_term)
1029
1094
 
1030
1095
  return [] if matches.empty?
@@ -1039,11 +1104,12 @@ module Howzit
1039
1104
  else
1040
1105
  titles = matches.map(&:title)
1041
1106
  res = Prompt.choose(titles, query: search_term)
1042
- old_matching = Howzit.options[:matching]
1043
- Howzit.options[:matching] = 'exact'
1044
- selected = res.flat_map { |title| find_topic(title) }
1045
- Howzit.options[:matching] = old_matching
1046
- selected
1107
+ # Convert selected titles back to topic objects from the original matches
1108
+ res.flat_map do |title|
1109
+ matched_topic = matches.find { |t| t.title == title }
1110
+ matched_topic || find_topic(title)[0]
1111
+ end.compact
1112
+
1047
1113
  end
1048
1114
  end
1049
1115
 
@@ -1065,7 +1131,15 @@ module Howzit
1065
1131
  end
1066
1132
 
1067
1133
  if !topic_matches.empty?
1068
- topic_matches.map! { |topic| topic.is_a?(String) ? find_topic(topic)[0] : topic }
1134
+ topic_matches.map! do |topic|
1135
+ if topic.is_a?(String)
1136
+ matches = find_topic(topic)
1137
+ matches.empty? ? nil : matches[0]
1138
+ elsif topic.is_a?(Howzit::Topic)
1139
+ topic
1140
+ end
1141
+ end
1142
+ topic_matches.compact! # Remove any nil values from failed matches
1069
1143
  topic_matches.each { |topic_match| output.push(process_topic(topic_match, Howzit.options[:run], single: true)) }
1070
1144
  else
1071
1145
  topics.each { |k| output.push(process_topic(k, false, single: false)) }
@@ -1107,11 +1181,11 @@ module Howzit
1107
1181
  # Run each topic with its specific arguments
1108
1182
  topic_specs.each do |topic_match, args|
1109
1183
  # Set arguments if provided, otherwise clear them
1110
- if args && !args.empty?
1111
- Howzit.arguments = args.split(/ *, */).map(&:render_arguments)
1112
- else
1113
- Howzit.arguments = []
1114
- end
1184
+ Howzit.arguments = if args && !args.empty?
1185
+ args.split(/ *, */).map(&:render_arguments)
1186
+ else
1187
+ []
1188
+ end
1115
1189
  output.push(process_topic(topic_match, Howzit.options[:run], single: true))
1116
1190
  end
1117
1191
  finalize_output(output)
data/lib/howzit/colors.rb CHANGED
@@ -288,8 +288,8 @@ module Howzit
288
288
  d: dark, b: bold, u: underline, i: italic, x: reset }
289
289
 
290
290
  result = fmt.empty? ? input : format(fmt, colors)
291
- # Unescape braces that were escaped to prevent color code interpretation
292
- result.gsub(/\\\{/, '{').gsub(/\\\}/, '}')
291
+ # Unescape braces and dollar signs that were escaped to prevent color code interpretation
292
+ result.gsub(/\\\{/, '{').gsub(/\\\}/, '}').gsub(/\\\$/, '$')
293
293
  end
294
294
  end
295
295
 
@@ -30,13 +30,13 @@ module Howzit
30
30
  symbol = entry[:success] ? '✅' : '❌'
31
31
  parts = ["#{symbol} "]
32
32
  if prefix_topic && entry[:topic] && !entry[:topic].empty?
33
- # Escape braces in topic name to prevent color code interpretation
34
- topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
33
+ # Escape braces and dollar signs in topic name to prevent color code interpretation
34
+ topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
35
35
  parts << "{bw}#{topic_escaped}{x}: "
36
36
  end
37
- # Escape braces in task name to prevent color code interpretation
38
- task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
39
- parts << "{by}#{task_escaped}{x}"
37
+ # Escape braces and dollar signs in task name to prevent color code interpretation
38
+ task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
39
+ parts << "{by}#{task_escaped} {x}"
40
40
  unless entry[:success]
41
41
  reason = entry[:exit_status] ? "exit code #{entry[:exit_status]}" : 'failed'
42
42
  parts << " {br}(#{reason}){x}"
@@ -82,15 +82,15 @@ module Howzit
82
82
  task_parts_plain = []
83
83
 
84
84
  if prefix_topic && entry[:topic] && !entry[:topic].empty?
85
- # Escape braces in topic name to prevent color code interpretation
86
- topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
85
+ # Escape braces and dollar signs in topic name to prevent color code interpretation
86
+ topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
87
87
  task_parts << "{bw}#{topic_escaped}{x}: "
88
88
  task_parts_plain << "#{entry[:topic]}: "
89
89
  end
90
90
 
91
- # Escape braces in task name to prevent color code interpretation
92
- task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
93
- task_parts << "{by}#{task_escaped}{x}"
91
+ # Escape braces and dollar signs in task name to prevent color code interpretation
92
+ task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
93
+ task_parts << "{by}#{task_escaped} {x}"
94
94
  task_parts_plain << entry[:task]
95
95
 
96
96
  unless entry[:success]
@@ -175,9 +175,43 @@ module Howzit
175
175
  when 'beginswith'
176
176
  /^#{self}/i
177
177
  when 'fuzzy'
178
- /#{split(//).join('.{0,3}?')}/i
178
+ # For fuzzy matching, use token-based matching where each word gets fuzzy character matching
179
+ # This allows "lst tst" to match "List Available Tests" by applying fuzzy matching to each token
180
+ words = split(/\s+/).reject(&:empty?)
181
+ if words.length > 1
182
+ # Multiple words: apply character-by-character fuzzy matching to each word token
183
+ # Then allow flexible matching between words
184
+ pattern = words.map do |w|
185
+ # Apply fuzzy matching to each word (character-by-character with up to 3 chars between)
186
+ w.split(//).map { |c| Regexp.escape(c) }.join('.{0,3}?')
187
+ end.join('.*')
188
+ /#{pattern}/i
189
+ else
190
+ # Single word: character-by-character fuzzy matching for flexibility
191
+ /#{split(//).join('.{0,3}?')}/i
192
+ end
193
+ when 'token'
194
+ # Token-based matching: match words in order with any text between them
195
+ # "list tests" matches "list available tests", "list of tests", etc.
196
+ words = split(/\s+/).reject(&:empty?)
197
+ if words.length > 1
198
+ pattern = words.map { |w| Regexp.escape(w) }.join('.*')
199
+ /#{pattern}/i
200
+ else
201
+ /#{Regexp.escape(self)}/i
202
+ end
179
203
  else
180
- /#{self}/i
204
+ # Default 'partial' mode: token-based matching for multi-word searches
205
+ # This allows "list tests" to match "list available tests"
206
+ words = split(/\s+/).reject(&:empty?)
207
+ if words.length > 1
208
+ # Token-based: match words in order with any text between
209
+ pattern = words.map { |w| Regexp.escape(w) }.join('.*')
210
+ /#{pattern}/i
211
+ else
212
+ # Single word: simple substring match
213
+ /#{Regexp.escape(self)}/i
214
+ end
181
215
  end
182
216
  end
183
217
 
data/lib/howzit/topic.rb CHANGED
@@ -37,7 +37,7 @@ module Howzit
37
37
  args.each_with_index do |arg, idx|
38
38
  arg_name, default = arg.split(/:/).map(&:strip)
39
39
 
40
- @named_args[arg_name] = if Howzit.arguments.count >= idx + 1
40
+ @named_args[arg_name] = if Howzit.arguments && Howzit.arguments.count >= idx + 1
41
41
  Howzit.arguments[idx]
42
42
  else
43
43
  default
@@ -175,6 +175,7 @@ module Howzit
175
175
  return [] if matches.empty?
176
176
 
177
177
  topic = matches[0]
178
+ return [] if topic.nil?
178
179
 
179
180
  rule = '{kKd}'
180
181
  color = '{Kyd}'
@@ -302,26 +303,31 @@ module Howzit
302
303
  title: title.dup, # Make a copy to avoid reference issues
303
304
  action: obj,
304
305
  parent: self }
306
+ # Set named_arguments before processing titles for variable substitution
307
+ Howzit.named_arguments = @named_args
305
308
  case cmd
306
309
  when /include/i
307
310
  if title =~ /\[(.*?)\] *$/
308
- Howzit.named_arguments = @named_args
309
311
  args = Regexp.last_match(1).split(/ *, */).map(&:render_arguments)
310
312
  Howzit.arguments = args
311
313
  arguments
312
314
  title.sub!(/ *\[.*?\] *$/, '')
313
- task_args[:title] = title
314
315
  end
316
+ # Apply variable substitution to title after bracket processing
317
+ task_args[:title] = title.render_arguments
315
318
 
316
319
  task_args[:type] = :include
317
320
  task_args[:arguments] = Howzit.named_arguments
318
321
  when /run/i
319
322
  task_args[:type] = :run
323
+ task_args[:title] = title.render_arguments
320
324
  when /copy/i
321
325
  task_args[:type] = :copy
322
326
  task_args[:action] = Shellwords.escape(obj)
327
+ task_args[:title] = title.render_arguments
323
328
  when /open|url/i
324
329
  task_args[:type] = :open
330
+ task_args[:title] = title.render_arguments
325
331
  end
326
332
 
327
333
  task_args
@@ -373,6 +379,8 @@ module Howzit
373
379
  if c[:cmd].nil?
374
380
  optional, default = define_optional(c[:optional2])
375
381
  title = c[:title2].nil? ? '' : c[:title2].strip
382
+ # Apply variable substitution to block title
383
+ title = title.render_arguments if title && !title.empty?
376
384
  block = c[:block]&.strip
377
385
  runnable << Howzit::Task.new({ type: :block,
378
386
  title: title,
@@ -3,5 +3,5 @@
3
3
  # Primary module for this gem.
4
4
  module Howzit
5
5
  # Current Howzit version.
6
- VERSION = '2.1.26'
6
+ VERSION = '2.1.28'
7
7
  end
data/lib/howzit.rb CHANGED
@@ -13,7 +13,7 @@ COLOR_FILE = 'theme.yaml'
13
13
  IGNORE_FILE = 'ignore.yaml'
14
14
 
15
15
  # Available options for matching method
16
- MATCHING_OPTIONS = %w[partial exact fuzzy beginswith].freeze
16
+ MATCHING_OPTIONS = %w[partial exact fuzzy beginswith token].freeze
17
17
 
18
18
  # Available options for multiple_matches method
19
19
  MULTIPLE_OPTIONS = %w[first best all choose].freeze
@@ -47,5 +47,25 @@ describe Howzit::RunReport do
47
47
  # Second line should be separator
48
48
  expect(lines[1]).to match(/^\|[\s:-]+\|[\s:-]+\|$/)
49
49
  end
50
+
51
+ it 'preserves dollar signs in task names without interfering with color codes' do
52
+ Howzit::RunReport.log({ topic: 'Test Topic', task: '$text$', success: true, exit_status: 0 })
53
+ Howzit::RunReport.log({ topic: 'Test', task: 'echo ${VAR}', success: true, exit_status: 0 })
54
+ plain = Howzit::RunReport.format.uncolor
55
+ expect(plain).to include('$text$')
56
+ expect(plain).to include('${VAR}')
57
+ # Verify dollar signs are preserved and not causing color code issues
58
+ expect(plain).not_to include('{x}')
59
+ expect(plain.scan(/\$\{x\}/).length).to eq(0)
60
+ end
61
+
62
+ it 'preserves dollar signs in topic names without interfering with color codes' do
63
+ Howzit.multi_topic_run = true
64
+ Howzit::RunReport.log({ topic: '$dollar$ Topic', task: 'Some Task', success: true, exit_status: 0 })
65
+ plain = Howzit::RunReport.format.uncolor
66
+ expect(plain).to include('$dollar$ Topic')
67
+ expect(plain).not_to include('{x}')
68
+ expect(plain.scan(/\$\{x\}/).length).to eq(0)
69
+ end
50
70
  end
51
71
 
data/spec/topic_spec.rb CHANGED
@@ -101,4 +101,33 @@ describe Howzit::Topic do
101
101
  expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▶ ls -1/)
102
102
  end
103
103
  end
104
+
105
+
106
+ describe '.arguments' do
107
+ before do
108
+ Howzit.arguments = []
109
+ end
110
+
111
+ it 'extracts named arguments from topic title with defaults' do
112
+ topic = Howzit::Topic.new('Test Topic (var1:default1, var2:default2)', 'Content')
113
+ expect(topic.named_args['var1']).to eq('default1')
114
+ expect(topic.named_args['var2']).to eq('default2')
115
+ end
116
+
117
+ it 'does nothing when title has no arguments' do
118
+ topic = Howzit::Topic.new('Test Topic', 'Content')
119
+ expect(topic.named_args).to eq({})
120
+ end
121
+
122
+ it 'cleans title after extracting arguments' do
123
+ topic = Howzit::Topic.new('Test Topic (var:val)', 'Content')
124
+ expect(topic.title).to eq('Test Topic')
125
+ end
126
+
127
+ it 'uses provided arguments over defaults' do
128
+ Howzit.arguments = ['provided_value']
129
+ topic = Howzit::Topic.new('Test Topic (var:default_value)', 'Content')
130
+ expect(topic.named_args['var']).to eq('provided_value')
131
+ end
132
+ end
104
133
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: howzit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.26
4
+ version: 2.1.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra