gm-notepad 0.0.11 → 0.0.12

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: 72cbb20c02dd2fa334bf57d7d88c40e7772d05ccf03bee599ddbf651e416c645
4
- data.tar.gz: 1e474a0b888297ae5655e68710f5d40efcfbb59030aac36dab60e4fc765043de
3
+ metadata.gz: 639ecbd6c3ab1d9ca709d743c23b88fbfc2deab18a25254bf3c27c71d1c4328e
4
+ data.tar.gz: e0adf1f064950a784c0a84349c92a7e10240990967a2c042166e2845e246d869
5
5
  SHA512:
6
- metadata.gz: 49a06ad0a6f85eddaefa70f9f05dd358f39f163cc3c7555f0116d2c645436260910ef8f4ec4b955e26bbf8d332a0957a6dfa401c39b3a7664a44c6f787f6be60
7
- data.tar.gz: a0f8bd008eb2220a4f8c68726aa96fcd68b110f50725b01091dc7ef5c57096e41d908674d4fa1bd46c0a552f61f01e68dddac3c508a499674d305361845363b4
6
+ metadata.gz: 45e58dd1073d6a3b269b7ee87ef30643833ba0f71737265a4197802577b9254bc97c2a91042ef566ee440c39ac4dc0f24782cedd61d1d54a7e8712d3c76e4b4c
7
+ data.tar.gz: b06fd07045eb893e31c832117fa849cadeccd0447a0386c5ee09a46e9eae6bdbe87decadc72f4c9264b0a182eb4784d3e0f2358c241f1430146b4f69798b0ccb
data/README.md CHANGED
@@ -184,7 +184,7 @@ You can also roll within a table. In the `gm-notepad` type the following:
184
184
  You won't get a "SamWise" or "FrodoWise" (or "FrodoWiseWise").
185
185
 
186
186
  To wrap up our first session, let's try one more thing. In your `gm-notepad`
187
- session type the following: `{first-name} owes [2d6]gp to {first-name}`:
187
+ session type the following: `{first-name} owes {2d6}gp to {first-name}`:
188
188
 
189
189
  ```console
190
190
  Frodo owes 3gp to SamWise
@@ -213,6 +213,7 @@ columns. _I am still working on retrieving by column names as well as rendering
213
213
  - [ ] Write expected interface document
214
214
  - [X] Handle `{critical[5]}`
215
215
  - [X] Allow `{critical[{2d6+1}]}` to roll the dice then lookup the value in the critical table
216
+ - [X] Handle `{critical[{2d6}]} for {2d6} damage`
216
217
  - [ ] For `{critical[{2d6+1}]}`, how to handle out of bounds
217
218
  - [X] Skip table lines that begin with `#`
218
219
  - [X] Skip processing input lines that begin with `#`
@@ -223,7 +224,7 @@ columns. _I am still working on retrieving by column names as well as rendering
223
224
  - [ ] Normalize `WriteToTableHandler` to deliver on `grep` and `index` behavior
224
225
  - [X] Gracefully handle requesting an entry from a table with an index that does not exist (e.g. with test data try `+name[23]`)
225
226
  - [X] Gracefully handle `+name[]`, where "name" is a registered table
226
- - [ ] Add time to live for line expansion (to prevent infinite loops); I suspect 100 to be reasonable
227
+ - [X] Add time to live for line expansion (to prevent infinite loops); I suspect 100 to be reasonable
227
228
  - [X] Enable "up" and "down" to scroll through history
228
229
  - [X] Add index name when rendering table entries
229
230
  - [ ] Gracefully handle loading a malformed data file (maybe?)
data/exe/gm-notepad CHANGED
@@ -39,6 +39,10 @@ OptionParser.new do |options|
39
39
  config[:table_extension] = table_extension
40
40
  end
41
41
 
42
+ options.on("-lTTL", "--time_to_live=TTL", Integer, "Per line of input, how many times to allow text expansion (Default: #{defaults.time_to_live.inspect})") do |time_to_live|
43
+ config[:time_to_live] = time_to_live
44
+ end
45
+
42
46
  options.on("-dDELIM", "--delimiter=DELIM", String, "Default column delimiter for tables (Default: #{defaults.column_delimiter.inspect})") do |column_delimiter|
43
47
  map = { "t" => "\t" }
44
48
  config[:column_delimiter] = map.fetch(column_delimiter) { column_delimiter }
@@ -1,21 +1,25 @@
1
1
  require 'dry-initializer'
2
2
  require 'gm/notepad/container'
3
+ require 'gm/notepad/line_renderer'
3
4
  require 'gm/notepad/throughput_text'
5
+ require 'gm/notepad/input_processor'
4
6
 
5
7
  module Gm
6
8
  module Notepad
7
9
  # Responsible for recording entries and then dumping them accordingly.
8
10
  class App
9
11
  extend Dry::Initializer
10
- option :renderer, default: -> { Container.resolve(:renderer) }
11
- option :input_processor, default: -> { Container.resolve(:input_processor) }
12
+ option :table_registry, default: -> { Container.resolve(:table_registry) }, reader: :private
12
13
  option :report_config, default: -> { Container.resolve(:config).report_config }, reader: :private
13
14
  option :list_tables, default: -> { Container.resolve(:config).list_tables }, reader: :private
14
15
 
15
- def initialize(*args)
16
+ def initialize(*args, input_processor: nil, renderer: nil)
16
17
  super
18
+ @renderer = renderer || LineRenderer.new(table_registry: table_registry)
19
+ @input_processor = input_processor || InputProcessor.new(table_registry: table_registry)
17
20
  open!
18
21
  end
22
+ attr_reader :renderer, :input_processor
19
23
 
20
24
  def process(text:)
21
25
  output = input_processor.convert_to_output(input: text)
@@ -4,19 +4,20 @@ module Gm
4
4
  class Config
5
5
  extend Dry::Configurable
6
6
 
7
- setting :report_config, false, reader: true
7
+ setting :column_delimiter, "|", reader: true
8
8
  setting :filesystem_directory, '.', reader: true
9
+ setting :include_original_command_as_comment, true, reader: true
9
10
  setting :index_entry_prefix, "index", reader: true
10
11
  setting :interactive_buffer, $stderr, reader: true
11
12
  setting :interactive_color, :faint, reader: true
12
- setting :output_color, false, reader: true
13
13
  setting :list_tables, false, reader: true
14
14
  setting :output_buffer, $stdout, reader: true
15
+ setting :output_color, false, reader: true
15
16
  setting :paths, ['.'], reader: true
16
- setting :column_delimiter, "|", reader: true
17
+ setting :report_config, false, reader: true
17
18
  setting :skip_readlines, false, reader: true
18
- setting :include_original_command_as_comment, true, reader: true
19
19
  setting :table_extension, '.txt', reader: true
20
+ setting :time_to_live, 20, reader: true
20
21
  setting :with_timestamp, false, reader: true
21
22
 
22
23
  def self.index_entry_prefix_regexp
@@ -6,11 +6,6 @@ module Gm
6
6
  class Container
7
7
  extend Dry::Container::Mixin
8
8
 
9
- register "input_processor" do
10
- require 'gm/notepad/input_processor'
11
- InputProcessor.new
12
- end
13
-
14
9
  register "config" do
15
10
  require 'gm/notepad/config'
16
11
  Config
@@ -21,11 +16,6 @@ module Gm
21
16
  TableRegistry.build_and_load
22
17
  end
23
18
 
24
- register "renderer" do
25
- require 'gm/notepad/line_renderer'
26
- LineRenderer.new
27
- end
28
-
29
19
  register "input_handler_registry" do
30
20
  # Order matters. The first registered will be the first to
31
21
  # answer "Can you handle the input?"
@@ -4,7 +4,7 @@ module Gm
4
4
  module Evaluators
5
5
  module DiceEvaluator
6
6
  def self.call(text:, fallback: text)
7
- if parsed_text = Dice.parse(text)
7
+ if parsed_text = Dice.parse(text.strip)
8
8
  parsed_text.evaluate.to_s
9
9
  else
10
10
  fallback.to_s
@@ -20,5 +20,14 @@ module Gm
20
20
  end
21
21
  alias to_buffer_message to_s
22
22
  end
23
+
24
+ class ExceededTimeToLiveError < RuntimeError
25
+ attr_reader :text_when_time_to_live_exceeded
26
+ def initialize(text:, time_to_live:, text_when_time_to_live_exceeded:)
27
+ @text_when_time_to_live_exceeded = text_when_time_to_live_exceeded
28
+ super(%(Expanding the given text "#{text}" exceed the time to live of #{time_to_live}))
29
+ end
30
+ alias to_buffer_message to_s
31
+ end
23
32
  end
24
33
  end
@@ -35,18 +35,7 @@ module Gm
35
35
  else
36
36
  expand_line = true
37
37
  end
38
- input.render_current_text(to_interactive: true , to_output: false, to_filesystem: true, expand_line: expand_line)
39
- end
40
-
41
- def lines
42
- if index
43
- elsif grep
44
- end
45
- if expand_line
46
- else
47
- end
48
- table_registry.append(table_name: table_name, line: input.text_to_evaluate, write: true)
49
- []
38
+ input.for_rendering(table_name: table_name, text: input.text_to_evaluate, to_interactive: true , to_output: false, to_filesystem: true, expand_line: expand_line)
50
39
  end
51
40
  end
52
41
  end
@@ -10,30 +10,35 @@ module Gm
10
10
  class LineEvaluator
11
11
  extend Dry::Initializer
12
12
  option :table_registry, default: -> { Container.resolve(:table_registry) }, reader: :private
13
+ option :time_to_live, default: -> { Container.resolve(:config).time_to_live }, reader: :private
13
14
 
14
- TABLE_NAME_REGEXP = %r{(?<table_name_container>\{(?<table_name>[^\{\}]+)\})}
15
15
  def call(line:, expand_line: true)
16
16
  input = ThroughputText.new(original_text: line, table_registry: table_registry)
17
17
  return input unless expand_line
18
- parse_table(input: input)
19
- parse_dice(input: input)
18
+ parse(input: input)
20
19
  input
21
20
  end
22
21
 
23
22
  private
24
23
 
25
- def parse_table(input:)
26
- while match = input.match(TABLE_NAME_REGEXP)
27
- table_lookup = Parameters::TableLookup.new(text: match[:table_name].strip, roll_dice: true)
28
- entry = table_registry.lookup(**table_lookup.parameters)
29
- input.sub!(match[:table_name_container], entry)
30
- end
31
- end
32
- DICE_REGEXP = %r{(?<dice_container>\[(?<dice>[^\]]+)\])}
33
- def parse_dice(input:)
34
- while match = input.match(DICE_REGEXP)
35
- evaluated_dice = Evaluators::DiceEvaluator.call(text: match[:dice], fallback: "(#{match[:dice]})")
36
- input.sub!(match[:dice_container], evaluated_dice)
24
+ TEXT_TO_EXPAND_REGEXP = %r{(?<text_container>\{(?<text>[^\{\}]+)\})}
25
+ def parse(input:)
26
+ lives = 0
27
+ while match = input.match(TEXT_TO_EXPAND_REGEXP)
28
+ lives += 1
29
+ if lives > time_to_live
30
+ raise ExceededTimeToLiveError.new(text: input.original_text, time_to_live: time_to_live, text_when_time_to_live_exceeded: input.to_s)
31
+ end
32
+ rolled_text = Evaluators::DiceEvaluator.call(text: match[:text])
33
+ # We sent the text through a dice roller. It came back unchanged, therefore
34
+ # the text is not a dice expression. Now expand the table.
35
+ if rolled_text == match[:text]
36
+ table_lookup = Parameters::TableLookup.new(text: match[:text], roll_dice: true)
37
+ entry = table_registry.lookup(**table_lookup.parameters)
38
+ input.sub!(match[:text_container], entry)
39
+ else
40
+ input.sub!(match[:text_container], rolled_text)
41
+ end
37
42
  end
38
43
  end
39
44
  end
@@ -11,6 +11,7 @@ module Gm
11
11
  option :with_timestamp, default: -> { Container[:config].with_timestamp }
12
12
  option :interactive_buffer, type: -> (buffer, renderer) { BufferWrapper.for_interactive(buffer: buffer) }, default: -> { Container[:config].interactive_buffer }
13
13
  option :output_buffer, type: -> (buffer, renderer) { BufferWrapper.for_output(buffer: buffer) }, default: -> { Container[:config].output_buffer }
14
+ option :table_registry, default: -> { Container.resolve(:table_registry) }
14
15
 
15
16
  def render(output:, as_of: Time.now)
16
17
  output.evaluate!
@@ -22,6 +23,10 @@ module Gm
22
23
  next unless line.to_output
23
24
  render_output(line, as_of: as_of)
24
25
  end
26
+ output.lines_for_rendering.each do |line|
27
+ next unless line.to_filesystem
28
+ render_filesystem(line)
29
+ end
25
30
  end
26
31
 
27
32
  def call(lines, to_output: false, to_interactive: true, as_of: Time.now)
@@ -51,6 +56,14 @@ module Gm
51
56
  end
52
57
  end
53
58
 
59
+ def render_filesystem(lines)
60
+ return unless lines.table_name
61
+ table_name = lines.table_name
62
+ each_expanded_line(lines: lines) do |line|
63
+ table_registry.append(table_name: table_name, line: line, write: true)
64
+ end
65
+ end
66
+
54
67
  # Gracefully expand the \t and \n for the output buffer
55
68
  def each_expanded_line(lines:)
56
69
  Array(lines).each do |unexpanded_line|
@@ -5,7 +5,7 @@ module Gm
5
5
  # Responsible for teasing apart the table logic
6
6
  class TableLookup
7
7
  def initialize(text:, roll_dice: false)
8
- @text = text
8
+ @text = text.strip
9
9
  @role_dice = false
10
10
  @parameters = {}
11
11
  extract_parameters!
@@ -15,6 +15,7 @@ module Gm
15
15
 
16
16
  def initialize(*args)
17
17
  super
18
+ @table = {}
18
19
  set_null_table_column_set!
19
20
  process(lines: lines)
20
21
  end
@@ -89,7 +90,6 @@ module Gm
89
90
 
90
91
  STARTS_WITH_COMMENT_REGEXP = %r{\A#}
91
92
  def process(lines:)
92
- @table = {}
93
93
  lines.each do |line|
94
94
  line = line.strip
95
95
  # Handle Comment
@@ -24,8 +24,6 @@ module Gm
24
24
  instance_exec(&block) if block_given?
25
25
  end
26
26
 
27
- attr_reader :line_evaluator, :registry
28
-
29
27
  def table_names
30
28
  registry.keys.sort
31
29
  end
@@ -65,6 +65,7 @@ module Gm
65
65
  option :to_interactive
66
66
  option :to_output
67
67
  option :to_filesystem, default: -> { false }
68
+ option :table_name, default: -> { nil }
68
69
  option :expand_line, default: -> { true }
69
70
  option :table_registry, default: -> { Container.resolve(:table_registry) }, reader: :private
70
71
 
@@ -1,5 +1,5 @@
1
1
  module Gm
2
2
  module Notepad
3
- VERSION = "0.0.11"
3
+ VERSION = "0.0.12"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gm-notepad
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Friesen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-01 00:00:00.000000000 Z
11
+ date: 2019-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dice_parser