gm-notepad 0.0.11 → 0.0.12

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: 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