gm-notepad 0.0.6 → 0.0.8

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: 6fad1534243d237bace667966a495af3e787a0bc67ef40283e96a2d7ca49942f
4
- data.tar.gz: b37925618ac94a01fdceadba354c641f704756ce55788c839a518e4e3a474b24
3
+ metadata.gz: da3bbc8cbf352187a313f8815110edef14d41c7c37e4f2dd1f3bb49e43200bcf
4
+ data.tar.gz: 12ffebdda56b6d2e3a4c43da401c884b8c1a659767ea618081792346530ca15c
5
5
  SHA512:
6
- metadata.gz: 80173f33eff4c3f0aa01f4ec706f2759d8f91b698b0c45872c299b94e0ac327f5deb1d9b2bf85fa468eaf28b9744f08aa7af67ccb20dd201fe8ce7159ba15e11
7
- data.tar.gz: 49ef7f14a885164ff70dc9e46bb2d05867fe53a9345cb5223efd2624fad4cad54e3f27d85f4aca4df0233cf973899f73786f1d824f958d9f09a8ceda837e7f3b
6
+ metadata.gz: fa277d748161cb37f2b1105d02d17cc551769f171953746bfd8aed13cd009c48fbb155a96c08a980f1c34ab66e6c6afa07cf42b804eac77cf5a5a79016533f4e
7
+ data.tar.gz: a0539f38a29bcce258255da060388f29cbeab6cd59505fbcb2af2f757f8094637d8b821f63e339f8002169ffe720b9346d5b10c5fd6a03ead9ad6ba759308116
data/README.md CHANGED
@@ -177,6 +177,10 @@ Hello SamWise
177
177
  The line with starting with `=>` is the `interactive` buffer. The other line
178
178
  is written to the `output` buffer.
179
179
 
180
+ You can also roll within a table. In the `gm-notepad` type the following:
181
+ `{first-name[1d4]}`. The system will output "Frodo", "Merry", "Pippin", or "Sam".
182
+ You won't get a "SamWise" or "FrodoWise" (or "FrodoWiseWise").
183
+
180
184
  To wrap up our first session, let's try one more thing. In your `gm-notepad`
181
185
  session type the following: `{first-name} owes [2d6]gp to {first-name}`:
182
186
 
@@ -213,7 +217,7 @@ entry has a 1 in 3 chance of being randomly chosen.
213
217
  - [X] Skip table lines that begin with `#`
214
218
  - [X] Skip processing input lines that begin with `#`
215
219
  - [X] Allow configuration to specify table delimiter
216
- - [ ] Add option to dump all tables to the given directory
220
+ - [ ] Raise load error if table index is a "dice" expression
217
221
  - [X] Allow configuration for where to dump data
218
222
  - [ ] Normalize `WriteToTableHandler` to use a renderer
219
223
  - [ ] Normalize `WriteToTableHandler` to deliver on `grep` and `index` behavior
@@ -221,7 +225,6 @@ entry has a 1 in 3 chance of being randomly chosen.
221
225
  - [X] Gracefully handle `+name[]`, where "name" is a registered table
222
226
  - [ ] Add time to live for line expansion (to prevent infinite loops); I suspect 100 to be reasonable
223
227
  - [X] Enable "up" and "down" to scroll through history
224
- - [ ] Add config that expands dice results while including the requested roll
225
228
  - [X] Add index name when rendering table entries
226
229
  - [ ] Gracefully handle loading a malformed data file (maybe?)
227
230
  - [X] Add concept of history
@@ -229,7 +232,8 @@ entry has a 1 in 3 chance of being randomly chosen.
229
232
  - [ ] Separate the InputHandler into pre-amble (e.g. allow overrides to where we are writing, determine what command we are writing)
230
233
  - [X] Create a configuration object that captures the initial input (reduce passing around parameters and persisting copies of the config)
231
234
  - [ ] Add concept of "journal entry"; its not a table (perhaps) but something that you could capture notes.
232
- - [ ] Add column handling `{table[][]}`
235
+ - [X] Add column handling `{table[][]}`
236
+ - [ ] Gracefully handle cell lookup when named cell for entry is not found
233
237
  - [X] Support `\{\{table}-name}` You should be able to do `\{\{culture}-name}` and first evaluate to `{arabic-name}` and then get a value from the `arabic-name` table
234
238
  - [X] Ensure index names are lower-case
235
239
  - [ ] Hit 100% spec coverage
@@ -245,3 +249,5 @@ entry has a 1 in 3 chance of being randomly chosen.
245
249
  - [ ] Add auto index expansion for "["
246
250
  - [ ] Determine feasibility of adding dice to the `{}` expansion syntax (instead of the `[]` syntax)
247
251
  - [ ] Add force write results to `output`
252
+ - [ ] Add option to dump all tables to the given directory
253
+ - [ ] Add config that expands dice results while including the requested roll
@@ -1,14 +1,32 @@
1
1
  # Write entry `1|entry one` to in memory table `basic_example`
2
- <#basic_example:1|entry one
2
+ <basic_example:1|entry one
3
+
3
4
  # Should render to interactive the internal help
4
5
  ?
6
+
7
+ # Should roll the dice
8
+ [2d6] goblins attack
9
+
5
10
  # Should render to interactive the given tables
6
11
  +
12
+
7
13
  # Should render to interactive the table `basic_example`
8
14
  +basic_example
15
+
9
16
  # Should render `entry one`
10
17
  {basic_example}
18
+
11
19
  # Should append entry `2|entry two` into memory table `basic_example`
12
20
  <basic_example:2|entry two
13
- # Should dump basic_example onto the file system
14
- +basic_example>
21
+
22
+ # Should show that there are two entries in `basic example`
23
+ +basic_example
24
+
25
+ # Should lookup entry 1 and 2
26
+ {basic_example[1]} and {basic_example[2]}
27
+
28
+ # Should lookup entry 1 and 2
29
+ {basic_example[1d1]}
30
+
31
+ # Should lookup entry 1 and 2
32
+ {2d6} {basic_example[1d1]}
data/exe/gm-notepad CHANGED
@@ -80,7 +80,7 @@ end
80
80
  begin
81
81
  @notepad = Gm::Notepad.new(**config)
82
82
  if config.fetch(:skip_readlines)
83
- input_getter = -> { print "#{config.fetch(:shell_prompt)} "; ARGF.gets }
83
+ input_getter = ARGF.method(:gets)
84
84
  else
85
85
  require 'gm/notepad/readline'
86
86
  input_getter = Gm::Notepad::Readline.input_getter(**config)
@@ -14,11 +14,10 @@ module Gm
14
14
  output_buffer: $stdout,
15
15
  paths: ['.'],
16
16
  column_delimiter: Gm::Notepad::DEFAULT_COLUMN_DELIMITER,
17
- shell_prompt: Gm::Notepad::DEFAULT_SHELL_PROMPT,
18
17
  skip_readlines: false,
19
18
  table_extension: '.txt',
20
19
  with_timestamp: false
21
- }.freeze
20
+ }
22
21
 
23
22
  # NOTE: ORDER MATTERS! I have a temporal dependency in these
24
23
  # defaults
@@ -0,0 +1,16 @@
1
+ require 'dice'
2
+ module Gm
3
+ module Notepad
4
+ module Evaluators
5
+ module DiceEvaluator
6
+ def self.call(text:, fallback: text)
7
+ if parsed_text = Dice.parse(text)
8
+ parsed_text.evaluate.to_s
9
+ else
10
+ fallback.to_s
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -9,13 +9,16 @@ module Gm
9
9
  end
10
10
  class MissingTableError < RuntimeError
11
11
  def initialize(name:)
12
+ @name = name
12
13
  super(%(Missing table "#{name}"))
13
14
  end
15
+ alias to_buffer_message to_s
14
16
  end
15
17
  class MissingTableEntryError < RuntimeError
16
18
  def initialize(table_name:, index:)
17
19
  super(%(Missing index "#{index}" for table "#{table_name}"))
18
20
  end
21
+ alias to_buffer_message to_s
19
22
  end
20
23
  end
21
24
  end
@@ -1,5 +1,6 @@
1
1
  require 'dice'
2
2
  require 'gm/notepad/parameters/table_lookup'
3
+ require 'gm/notepad/evaluators/dice_evaluator'
3
4
  module Gm
4
5
  module Notepad
5
6
  # Responsible for recording entries and then dumping them accordingly.
@@ -20,15 +21,8 @@ module Gm
20
21
 
21
22
  def parse_table(text:)
22
23
  while match = text.match(TABLE_NAME_REGEXP)
23
- table_lookup = Parameters::TableLookup.new(text: match[:table_name].strip)
24
- if table_lookup.index
25
- if index = Dice.parse(table_lookup.index)
26
- table_lookup.index = index.evaluate
27
- end
28
- entry = table_registry.lookup(index: table_lookup.index, table_name: table_lookup.table_name)
29
- else
30
- entry = table_registry.lookup(table_name: table_lookup.table_name)
31
- end
24
+ table_lookup = Parameters::TableLookup.new(text: match[:table_name].strip, roll_dice: true)
25
+ entry = table_registry.lookup(**table_lookup.parameters)
32
26
  text = text.sub(match[:table_name_container], entry)
33
27
  end
34
28
  text
@@ -36,11 +30,7 @@ module Gm
36
30
  DICE_REGEXP = %r{(?<dice_container>\[(?<dice>[^\]]+)\])}
37
31
  def parse_dice(text:)
38
32
  while match = text.match(DICE_REGEXP)
39
- if parsed_dice = Dice.parse(match[:dice])
40
- evaluated_dice = "#{parsed_dice.evaluate}"
41
- else
42
- evaluated_dice = "(#{match[:dice]})"
43
- end
33
+ evaluated_dice = Evaluators::DiceEvaluator.call(text: match[:dice], fallback: "(#{match[:dice]})")
44
34
  text = text.sub(match[:dice_container], evaluated_dice)
45
35
  end
46
36
  text
@@ -20,6 +20,7 @@ module Gm
20
20
  private
21
21
 
22
22
  def open!
23
+ renderer.call("Welcome to gm-notepad. type \"?\" for help.", to_interactive: true, to_output: false)
23
24
  return unless config.report_config
24
25
  lines = ["# Configuration Parameters:"]
25
26
  config.each_pair do |key, value|
@@ -1,43 +1,73 @@
1
+ require 'gm/notepad/evaluators/dice_evaluator'
1
2
  module Gm
2
3
  module Notepad
3
4
  module Parameters
4
5
  # Responsible for teasing apart the table logic
5
6
  class TableLookup
6
- WITH_GREP_REGEXP = %r{(?<declaration>\/(?<grep>[^\/]+)/)}
7
- WITH_INDEX_REGEXP = %r{(?<declaration>\[(?<index>[^\]]+)\])}
8
- WITH_EMPTY_INDEX_REGEX = %r{(?<declaration>\[\])}
9
- WITH_EMPTY_GREP_REGEX = %r{(?<declaration>\/\/)}
10
-
11
- def initialize(text:)
7
+ def initialize(text:, roll_dice: false)
12
8
  @text = text
9
+ @role_dice = false
10
+ @parameters = {}
13
11
  extract_parameters!
12
+ roll_them_bones! if roll_dice
14
13
  end
15
14
 
16
- attr_accessor :index, :grep, :table_name
15
+ attr_reader :cell, :index, :grep, :table_name
17
16
 
18
17
  def parameters
19
18
  parameters = { table_name: table_name }
20
19
  parameters[:grep] = grep if grep
21
20
  parameters[:index] = index if index
21
+ parameters[:cell] = cell if cell
22
22
  parameters
23
23
  end
24
24
 
25
25
  private
26
+
27
+ attr_writer :cell, :index, :grep, :table_name
28
+
29
+ def roll_them_bones!
30
+ if index
31
+ self.index = Evaluators::DiceEvaluator.call(text: index)
32
+ end
33
+ if cell
34
+ self.cell = Evaluators::DiceEvaluator.call(text: cell)
35
+ end
36
+ end
37
+
38
+ WITH_GREP_REGEXP = %r{(?<declaration>\/(?<found>[^\/]+)/)}
39
+ WITH_INDEX_REGEXP = %r{(?<declaration>\[(?<found>[^\]]+)\])}
40
+ CELL_WITHOUT_INDEX_REGEXP = %r{(?<declaration>\[\]\[(?<found>[^\]]+)\])}
41
+ EMPTY_INDEX_EMPTY_CELL_REGEXP = %r{(?<declaration>\[\]\[\])}
42
+ WITH_EMPTY_INDEX_REGEX = %r{(?<declaration>\[\])}
43
+ WITH_EMPTY_GREP_REGEX = %r{(?<declaration>\/\/)}
44
+
26
45
  def extract_parameters!
27
- @parameters = {}
28
46
  text = @text
29
- if match = WITH_EMPTY_INDEX_REGEX.match(text)
47
+ if match = EMPTY_INDEX_EMPTY_CELL_REGEXP.match(text)
48
+ text = text.sub(match[:declaration], '')
49
+ elsif match = CELL_WITHOUT_INDEX_REGEXP.match(text)
50
+ text = text.sub(match[:declaration], '')
51
+ self.cell = match[:found]
52
+ elsif match = WITH_EMPTY_INDEX_REGEX.match(text)
30
53
  text = text.sub(match[:declaration], '')
31
54
  elsif match = WITH_INDEX_REGEXP.match(text)
32
55
  text = text.sub(match[:declaration], '')
33
- @index = match[:index]
56
+ self.index = match[:found]
57
+ # Moving on to the cell
58
+ if match = WITH_EMPTY_INDEX_REGEX.match(text)
59
+ text = text.sub(match[:declaration], '')
60
+ elsif match = WITH_INDEX_REGEXP.match(text)
61
+ text = text.sub(match[:declaration], '')
62
+ self.cell = match[:found]
63
+ end
34
64
  elsif match = WITH_EMPTY_GREP_REGEX.match(text)
35
65
  text = text.sub(match[:declaration], '')
36
66
  elsif match = WITH_GREP_REGEXP.match(text)
37
67
  text = text.sub(match[:declaration], '')
38
- @grep = match[:grep]
68
+ self.grep = match[:found]
39
69
  end
40
- @table_name = text.downcase
70
+ self.table_name = text.downcase
41
71
  end
42
72
  end
43
73
  end
@@ -29,7 +29,7 @@ module Gm
29
29
  ::Readline.output = $stderr
30
30
 
31
31
  def self.input_getter(**config)
32
- -> { ::Readline.readline("#{config.fetch(:shell_prompt, ">")} ", true) }
32
+ -> { ::Readline.readline("", true) }
33
33
  end
34
34
  end
35
35
  end
@@ -8,15 +8,15 @@ module Gm
8
8
  process(lines: lines)
9
9
  end
10
10
 
11
- def lookup(index: false)
12
- if index
13
- begin
14
- @table.fetch(index.to_s)
15
- rescue KeyError
16
- raise MissingTableEntryError.new(table_name: table_name, index: index.to_s)
17
- end
11
+ def lookup(index: false, cell: false)
12
+ if index && cell
13
+ lookup_entry_by(index: index).lookup(cell: cell)
14
+ elsif index
15
+ lookup_entry_by(index: index)
16
+ elsif cell
17
+ lookup_random_entry.lookup(cell: cell)
18
18
  else
19
- @table.values[random_index]
19
+ lookup_random_entry
20
20
  end
21
21
  end
22
22
 
@@ -45,6 +45,18 @@ module Gm
45
45
 
46
46
  private
47
47
 
48
+ def lookup_entry_by(index:)
49
+ begin
50
+ @table.fetch(index.to_s)
51
+ rescue KeyError
52
+ raise MissingTableEntryError.new(table_name: table_name, index: index.to_s)
53
+ end
54
+ end
55
+
56
+ def lookup_random_entry
57
+ @table.values[random_index]
58
+ end
59
+
48
60
  attr_accessor :filename, :config
49
61
  attr_reader :table_name
50
62
 
@@ -60,7 +72,7 @@ module Gm
60
72
  @table = {}
61
73
  lines.each do |line|
62
74
  next if line[0] == '#'
63
- entry = TableEntry.new(line: line, **config)
75
+ entry = TableEntry.new(line: line, config: config)
64
76
  entry.lookup_range.each do |i|
65
77
  key = i.to_s
66
78
  raise DuplicateKeyError.new(key: table_name, object: self) if @table.key?(key)
@@ -4,7 +4,9 @@ module Gm
4
4
  TABLE_ENTRY_RANGE_MARKER = "-".freeze
5
5
  class TableEntry
6
6
  Configuration.init!(target: self, from_config: [:column_delimiter], additional_params: [:line]) do
7
- self.lookup_column, self.entry_column = line.split(column_delimiter)
7
+ row = line.split(column_delimiter)
8
+ self.index = row.shift
9
+ self.cells = row
8
10
  end
9
11
 
10
12
  include Comparable
@@ -12,30 +14,40 @@ module Gm
12
14
  to_str <=> String(other)
13
15
  end
14
16
 
17
+ def lookup(cell:)
18
+ # TODO: Need to deal with named columns
19
+ cells[cell.to_i]
20
+ end
21
+
15
22
  NUMBER_RANGE_REGEXP = %r{(?<left>\d+) *- *(?<right>\d+)}
16
23
  def lookup_range
17
- if match = NUMBER_RANGE_REGEXP.match(lookup_column)
24
+ if match = NUMBER_RANGE_REGEXP.match(index)
18
25
  (match[:left].to_i..match[:right].to_i).map(&:to_s)
19
26
  else
20
- [lookup_column]
27
+ [index]
21
28
  end
22
29
  end
23
30
 
24
- attr_reader :lookup_column, :entry_column
31
+ attr_reader :index, :cells
32
+
33
+ def entry
34
+ cells.join("\t")
35
+ end
36
+ alias entry_column entry
25
37
 
26
38
  def to_s
27
- "[#{lookup_column}]\t#{entry_column}"
39
+ "[#{index}]\t#{entry}"
28
40
  end
29
- alias to_str entry_column
41
+ alias to_str entry
30
42
 
31
43
  private
32
44
 
33
- def lookup_column=(input)
34
- @lookup_column = input.strip.downcase.freeze
45
+ def index=(input)
46
+ @index = input.strip.downcase.freeze
35
47
  end
36
48
 
37
- def entry_column=(input)
38
- @entry_column = input.strip.freeze
49
+ def cells=(input)
50
+ @cells = Array(input).map { |i| i.strip.freeze }.freeze
39
51
  end
40
52
  end
41
53
  end
@@ -59,15 +59,10 @@ module Gm
59
59
  end
60
60
 
61
61
  def lookup(table_name:, **kwargs)
62
- # TODO: Push this onto the table, as it removes nosy neighbor syndrom
63
- begin
64
- table = fetch_table(name: table_name)
65
- table.lookup(**kwargs)
66
- rescue MissingTableError
67
- "(undefined table_name: #{table_name.inspect})"
68
- rescue KeyError
69
- "(missing entry for #{kwargs.inspect})"
70
- end
62
+ table = fetch_table(name: table_name)
63
+ table.lookup(**kwargs)
64
+ rescue MissingTableError, MissingTableEntryError => e
65
+ e.to_buffer_message
71
66
  end
72
67
 
73
68
  def evaluate(line:)
@@ -1,5 +1,5 @@
1
1
  module Gm
2
2
  module Notepad
3
- VERSION = "0.0.6"
3
+ VERSION = "0.0.8"
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.6
4
+ version: 0.0.8
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-07-27 00:00:00.000000000 Z
11
+ date: 2019-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dice_parser
@@ -146,6 +146,7 @@ files:
146
146
  - lib/gm/notepad.rb
147
147
  - lib/gm/notepad/configuration.rb
148
148
  - lib/gm/notepad/defaults.rb
149
+ - lib/gm/notepad/evaluators/dice_evaluator.rb
149
150
  - lib/gm/notepad/exceptions.rb
150
151
  - lib/gm/notepad/input_handler_registry.rb
151
152
  - lib/gm/notepad/input_handlers/comment_handler.rb