rollio 0.1.0 → 0.1.1
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 +4 -4
- data/Gemfile +2 -0
- data/README.md +8 -6
- data/data/defy_danger.json +10 -0
- data/data/examples.json +24 -0
- data/exe/rollio +5 -0
- data/lib/rollio.rb +70 -1
- data/lib/rollio/cli.rb +65 -0
- data/lib/rollio/range.rb +121 -0
- data/lib/rollio/range_set.rb +26 -0
- data/lib/rollio/registry.rb +13 -309
- data/lib/rollio/roller.rb +18 -0
- data/lib/rollio/schemas/entry_schema.rb +24 -0
- data/lib/rollio/schemas/table_schema.rb +13 -0
- data/lib/rollio/table.rb +45 -0
- data/lib/rollio/table_set.rb +40 -0
- data/lib/rollio/version.rb +1 -1
- data/rollio.gemspec +4 -0
- metadata +71 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6d9919949718ff310a8dfdc0100df7c723b65674f43434e750412c52383b265
|
4
|
+
data.tar.gz: 7fd4483fd44dec675c22ace6269e1e4e95313c81ad4b84d8f0508cad7b8eb2fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37ee8ea172926651aa22d54479b369752685278544ca5a93a8425361ba6e98ae63daad182485e0a789058638394b3998a6bd68eaf254072b358aed0966c1c7dc
|
7
|
+
data.tar.gz: 6c31a6c62645d7bfc6d93f8774ef5a864ae221e0d077fb37243e9105d561b16921040dbd64189233c502b6aa4a2a28ec92d44fdd88aae2b695405ec2bf957fff
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,14 +4,16 @@ A tool for loading random tables, rolling on those tables, and rendering the out
|
|
4
4
|
|
5
5
|
## Todo List
|
6
6
|
|
7
|
-
- [
|
7
|
+
- [X] Create schema to define valid JSON document
|
8
8
|
- [ ] Integrate schema validation for loaded JSON document
|
9
|
-
- [
|
10
|
-
- [
|
9
|
+
- [X] Allow inner-table logic\*
|
10
|
+
- [X] Create structure for loading tables
|
11
11
|
- [ ] Create command line tool
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
- [X] List available tables (with help) (e.g. `rollio roll -h`)
|
13
|
+
- [ ] Look to parameterization of table rolls
|
14
|
+
- [X] Roll on tables (e.g. `rollio roll background`)
|
15
|
+
- [ ] Create structure for SWN batch of tables to roll at once
|
16
|
+
- [ ] Add ability to roll a dice expression via `rollio roll`
|
15
17
|
|
16
18
|
\* - By inner table logic I'm referring to "On a d10 table, when you roll a 9 or 10, roll on this table twice using a d8"
|
17
19
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
{
|
2
|
+
"key": "defy_danger",
|
3
|
+
"label": "Defy Danger",
|
4
|
+
"roll": "2d6",
|
5
|
+
"entries": [
|
6
|
+
{ "range": [-1,0,1,2,3,4,5,6], "result": "You do it"},
|
7
|
+
{ "range": [7,8,9], "result": "You stumble, hesitate, or flinch: the GM will offer you a worse outcome, hard bargain, or ugly choice." },
|
8
|
+
{ "range": [10,11,12,13,14,15,16], "result": "You flounder: the GM will make a hard move"}
|
9
|
+
]
|
10
|
+
}
|
data/data/examples.json
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
[{
|
2
|
+
"key": "table-a",
|
3
|
+
"roll": "2d6",
|
4
|
+
"entries": [
|
5
|
+
{ "range": [2,3,4,5,6], "roll_on": "table-b", "with": "1d3", "times": 2},
|
6
|
+
{ "range": [7], "result": "Yolo" },
|
7
|
+
{ "range": [8,9,10,11,12], "inner_table": {
|
8
|
+
"roll": "1d4",
|
9
|
+
"entries": [
|
10
|
+
{ "range": [1,2,3], "result": "Yes" },
|
11
|
+
{ "range": [4], "result": "No" }
|
12
|
+
]
|
13
|
+
}
|
14
|
+
}
|
15
|
+
]},{
|
16
|
+
"key": "table-b",
|
17
|
+
"roll": "1d6",
|
18
|
+
"entries": [
|
19
|
+
{ "range": [1], "result": "least result from sub-table" },
|
20
|
+
{ "range": [2,3,4,5], "result": "mid-range result from sub-table" },
|
21
|
+
{ "range": [6], "result": "greatest result from sub-table" }
|
22
|
+
]
|
23
|
+
}
|
24
|
+
]
|
data/exe/rollio
ADDED
data/lib/rollio.rb
CHANGED
@@ -1,6 +1,75 @@
|
|
1
1
|
require "rollio/version"
|
2
2
|
require "rollio/registry"
|
3
|
+
require 'json'
|
4
|
+
require 'hanami/utils/hash'
|
3
5
|
|
4
6
|
module Rollio
|
5
|
-
#
|
7
|
+
# @api private
|
8
|
+
# @example
|
9
|
+
# document = [{
|
10
|
+
# key: '1-a',
|
11
|
+
# roll: '2d6',
|
12
|
+
# entries: [
|
13
|
+
# { range: [2,3,4,5,6], roll_on: '1-b', with: '1d3', times: 2},
|
14
|
+
# { range: [7], result: 'Yolo' },
|
15
|
+
# { range: [8,9,10,11,12], inner_table: {
|
16
|
+
# roll: '1d4',
|
17
|
+
# entries: [
|
18
|
+
# { range: [1,2,3], result: 'Yes' },
|
19
|
+
# { range: [4], result: 'No' }
|
20
|
+
# ]
|
21
|
+
# }
|
22
|
+
# }
|
23
|
+
# },{
|
24
|
+
# key: '1-b',
|
25
|
+
# roll: '1d6',
|
26
|
+
# entries: [
|
27
|
+
# { range: [1,2,3,4,5,6], result: 'sub-table' }
|
28
|
+
# ]
|
29
|
+
# }
|
30
|
+
# ]
|
31
|
+
# registry = Rollio::Registry.load(document)
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# registry = Rollio::Registry.load do
|
35
|
+
# table('1') do
|
36
|
+
# roll('1d5')
|
37
|
+
# entry(1, 'Yes!')
|
38
|
+
# entry(2..5, 'No!')
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# @return [Rollio::Registry, #roll_on]
|
42
|
+
# @todo Add document schema and validation
|
43
|
+
def self.load(document = nil, context = self, &block)
|
44
|
+
if document
|
45
|
+
Registry.new do |registry|
|
46
|
+
document.each do |data|
|
47
|
+
context.load_a_table(registry: registry, data: data, context: context)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
else
|
51
|
+
Registry.new(&block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
# @todo Does the guts of this logic make sense here?
|
57
|
+
def self.load_a_table(registry: , data:, context: self, key: nil)
|
58
|
+
key ||= data.fetch(:key)
|
59
|
+
label = data.fetch(:label, key)
|
60
|
+
table = registry.table(key, label: label)
|
61
|
+
table.roll(data.fetch(:roll))
|
62
|
+
data.fetch(:entries).each do |table_entry|
|
63
|
+
range = table_entry.fetch(:range)
|
64
|
+
if table_entry.key?(:roll_on)
|
65
|
+
table.entry(range, **table_entry)
|
66
|
+
elsif table_entry.key?(:result)
|
67
|
+
table.entry(range, table_entry.fetch(:result))
|
68
|
+
elsif table_entry.key?(:inner_table)
|
69
|
+
inner_table = table_entry.fetch(:inner_table)
|
70
|
+
entry = table.entry(range, inner_table: true)
|
71
|
+
context.load_a_table(registry: registry, data: inner_table, context: context, key: entry.key)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
6
75
|
end
|
data/lib/rollio/cli.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'rollio'
|
3
|
+
module Rollio
|
4
|
+
class CLI < Thor
|
5
|
+
option(
|
6
|
+
:source,
|
7
|
+
aliases: '-s',
|
8
|
+
required: true,
|
9
|
+
default: File.join(ENV['HOME'], '.rollio'),
|
10
|
+
desc: "The <source> directory for tables to load into rollio"
|
11
|
+
)
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
register!
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "list", "List the registered tables"
|
18
|
+
long_desc <<-LONGDESC
|
19
|
+
`rollio list` will print out a list of all registered tables
|
20
|
+
LONGDESC
|
21
|
+
option(
|
22
|
+
:delimiter,
|
23
|
+
aliases: '-d',
|
24
|
+
desc: "The <delimiter> used to separate the table entries"
|
25
|
+
)
|
26
|
+
option(:help, aliases: '-h')
|
27
|
+
def list
|
28
|
+
help(__method__) and return if options[:help]
|
29
|
+
$stdout.puts @registry.table_names.join(options.fetch(:delimiter, "\n"))
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "audit", "Audit the tables in <source> to ensure validity"
|
33
|
+
option(:help, aliases: '-h')
|
34
|
+
def audit
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "roll <table>", "Roll on the given table"
|
38
|
+
option(:help, aliases: '-h')
|
39
|
+
def roll(table)
|
40
|
+
help(__method__) and return if options[:help]
|
41
|
+
$stdout.puts @registry.roll_on(table)
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "render", "Render the stored tables"
|
45
|
+
option(:help, aliases: '-h')
|
46
|
+
def render
|
47
|
+
help(__method__) and return if options[:help]
|
48
|
+
$stdout.puts @registry.render
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def register!
|
54
|
+
@registry = Rollio.load
|
55
|
+
Dir.glob("#{options[:source]}/**/*.json").each do |filename|
|
56
|
+
tables = JSON.parse(File.read(filename))
|
57
|
+
tables = [tables] unless tables.is_a?(Array)
|
58
|
+
tables.each do |table|
|
59
|
+
data = Hanami::Utils::Hash.deep_symbolize(table)
|
60
|
+
Rollio.load_a_table(registry: @registry, data: data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/rollio/range.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
module Rollio
|
2
|
+
module Range
|
3
|
+
def self.new(table:, range:, result:, roll_on: nil, inner_table: nil, inner_table_config: nil, times: 1, with: nil)
|
4
|
+
if result
|
5
|
+
Result.new(table: table, range: range, result: result, times: times)
|
6
|
+
elsif roll_on
|
7
|
+
RollOn.new(table: table, range: range, roll_on: roll_on, times: times, with: with)
|
8
|
+
elsif inner_table
|
9
|
+
InnerRollOn.new(table: table, range: range, times: times)
|
10
|
+
elsif inner_table_config
|
11
|
+
InnerTable.new(table: table, range: range, inner_table: inner_table_config, times: times)
|
12
|
+
else
|
13
|
+
raise "Hello"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Base
|
18
|
+
attr_reader :table, :range, :times
|
19
|
+
def initialize(table:, range:, times:, **kwargs)
|
20
|
+
@table = table
|
21
|
+
self.range = range
|
22
|
+
@times = times
|
23
|
+
end
|
24
|
+
|
25
|
+
def key
|
26
|
+
"#{table.key} (Sub #{range})"
|
27
|
+
end
|
28
|
+
|
29
|
+
extend Comparable
|
30
|
+
def <=>(other)
|
31
|
+
range.first <=> other.range.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def render
|
35
|
+
if range.first == range.last
|
36
|
+
puts "#{range.first}\t#{result}"
|
37
|
+
else
|
38
|
+
puts "#{range.first}-#{range.last}\t#{result}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def result
|
43
|
+
raise NotImplementedError
|
44
|
+
end
|
45
|
+
|
46
|
+
extend Forwardable
|
47
|
+
def_delegator :table, :table_set
|
48
|
+
|
49
|
+
def include?(value)
|
50
|
+
if @range.respond_to?(:include?)
|
51
|
+
@range.include?(value)
|
52
|
+
else
|
53
|
+
@range == value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def range=(input)
|
58
|
+
@range = Array(input)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
private_constant :Base
|
62
|
+
|
63
|
+
class Result < Base
|
64
|
+
attr_reader :result
|
65
|
+
def initialize(result:, **kwargs)
|
66
|
+
super(**kwargs)
|
67
|
+
@result = result
|
68
|
+
end
|
69
|
+
|
70
|
+
def roll!
|
71
|
+
[@result]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
private_constant :Result
|
75
|
+
|
76
|
+
class RollOn < Base
|
77
|
+
attr_reader :with
|
78
|
+
def initialize(roll_on:, **kwargs)
|
79
|
+
super(**kwargs)
|
80
|
+
@roll_on = roll_on
|
81
|
+
@with = kwargs[:with]
|
82
|
+
end
|
83
|
+
|
84
|
+
def roll!
|
85
|
+
(1..times).map { table_set.roll_on(@roll_on, with: with) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def result
|
89
|
+
"Roll on #{@roll_on}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
private_constant :RollOn
|
93
|
+
|
94
|
+
class InnerRollOn < Base
|
95
|
+
def roll!
|
96
|
+
(1..times).map { table_set.roll_on(key) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def result
|
100
|
+
"Roll on #{key}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class InnerTable < Base
|
105
|
+
def initialize(inner_table:, **kwargs)
|
106
|
+
super(**kwargs)
|
107
|
+
@table.table_set.add(key, &inner_table)
|
108
|
+
end
|
109
|
+
|
110
|
+
def roll!
|
111
|
+
(1..times).map { table_set.roll_on(key) }
|
112
|
+
end
|
113
|
+
|
114
|
+
def result
|
115
|
+
"Roll on #{key}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
private_constant :InnerTable
|
119
|
+
end
|
120
|
+
private_constant :Range
|
121
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rollio/range'
|
2
|
+
module Rollio
|
3
|
+
class RangeSet
|
4
|
+
def initialize(table:)
|
5
|
+
@table = table
|
6
|
+
@ranges = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def render
|
10
|
+
@ranges.sort.each do |range|
|
11
|
+
range.render
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def resolve(roll:)
|
16
|
+
@ranges.detect { |range| range.include?(roll) }.roll!
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(range:, **kwargs)
|
20
|
+
range_object = Range.new(range: range, **kwargs)
|
21
|
+
@ranges << range_object
|
22
|
+
range_object
|
23
|
+
end
|
24
|
+
end
|
25
|
+
private_constant :RangeSet
|
26
|
+
end
|
data/lib/rollio/registry.rb
CHANGED
@@ -1,332 +1,36 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'dice' # from dice_parser
|
3
|
+
require 'rollio/table_set'
|
3
4
|
|
4
5
|
module Rollio
|
5
6
|
# Responsible for registering random tables and exposing a means of rolling on those tables.
|
6
7
|
class Registry
|
7
|
-
# @api
|
8
|
-
# @example
|
9
|
-
# document = [{
|
10
|
-
# key: '1-a',
|
11
|
-
# roll: '2d6',
|
12
|
-
# entries: [
|
13
|
-
# { range: [2,3,4,5,6], roll_on: '1-b'},
|
14
|
-
# { range: [7], result: 'Yolo' },
|
15
|
-
# { range: [8,9,10,11,12], inner_table: {
|
16
|
-
# roll: '1d4',
|
17
|
-
# entries: [
|
18
|
-
# { range: [1,2,3], result: 'Yes' },
|
19
|
-
# { range: [4], result: 'No' }
|
20
|
-
# ]
|
21
|
-
# }
|
22
|
-
# }
|
23
|
-
# },{
|
24
|
-
# key: '1-b',
|
25
|
-
# roll: '1d6',
|
26
|
-
# entries: [
|
27
|
-
# { range: [1,2,3,4,5,6], result: 'sub-table' }
|
28
|
-
# ]
|
29
|
-
# }
|
30
|
-
# ]
|
31
|
-
# registry = Rollio::Registry.load(document)
|
32
|
-
#
|
33
|
-
# @example
|
34
|
-
# registry = Rollio::Registry.load do
|
35
|
-
# table('1') do
|
36
|
-
# roll('1d5')
|
37
|
-
# entry(1, 'Yes!')
|
38
|
-
# entry(2..5, 'No!')
|
39
|
-
# end
|
40
|
-
# end
|
41
|
-
# @return [Rollio::Registry, #roll_on]
|
42
|
-
# @todo Add document schema and validation
|
43
|
-
# @todo Expose #load method to allow additional loading outside of initialization
|
44
|
-
def self.load(document = nil, context = self, &block)
|
45
|
-
if document
|
46
|
-
Registry.new do |registry|
|
47
|
-
document.each do |data|
|
48
|
-
context.load_a_table(registry: registry, data: data, context: context)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
else
|
52
|
-
Registry.new(&block)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# @api private
|
57
|
-
def self.load_a_table(registry:, data:, context:, key: nil)
|
58
|
-
key ||= data.fetch(:key)
|
59
|
-
label = data.fetch(:label, key)
|
60
|
-
table = registry.table(key, label: label)
|
61
|
-
table.roll(data.fetch(:roll))
|
62
|
-
data.fetch(:entries).each do |table_entry|
|
63
|
-
range = table_entry.fetch(:range)
|
64
|
-
if table_entry.key?(:roll_on)
|
65
|
-
table.entry(range, roll_on: table_entry.fetch(:roll_on), times: table_entry.fetch(:times, 1))
|
66
|
-
elsif table_entry.key?(:result)
|
67
|
-
table.entry(range, table_entry.fetch(:result))
|
68
|
-
elsif table_entry.key?(:inner_table)
|
69
|
-
inner_table = table_entry.fetch(:inner_table)
|
70
|
-
entry = table.entry(range, inner_table: true)
|
71
|
-
Registry.load_a_table(registry: registry, data: inner_table, context: context, key: entry.key)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
attr_reader :table_set
|
8
|
+
# @api public
|
77
9
|
def initialize(&block)
|
78
|
-
|
10
|
+
self.table_set = TableSet.new(registry: self)
|
79
11
|
instance_exec(self, &block) if block_given?
|
80
12
|
end
|
81
13
|
|
14
|
+
attr_accessor :table_set
|
15
|
+
private :table_set=
|
16
|
+
|
82
17
|
# @api private
|
83
18
|
# @param key [String] The key of the table you want to roll on
|
84
19
|
# @see Registry::Table#key for details
|
85
20
|
# @todo Consider adding a modifier (eg. `roll_on(key, with: -2)`)
|
86
|
-
def roll_on(key)
|
87
|
-
|
21
|
+
def roll_on(key, **kwargs)
|
22
|
+
table_set.roll_on(key, **kwargs)
|
88
23
|
end
|
89
24
|
|
25
|
+
# @api private
|
26
|
+
# The exposed method for adding a table to the registry
|
90
27
|
def table(*args, &block)
|
91
|
-
|
28
|
+
table_set.add(*args, &block)
|
92
29
|
end
|
93
30
|
|
94
31
|
extend Forwardable
|
95
32
|
def_delegator :table_set, :render
|
96
|
-
|
97
|
-
class TableSet
|
98
|
-
extend Forwardable
|
99
|
-
|
100
|
-
def initialize(registry:)
|
101
|
-
@registry = registry
|
102
|
-
@tables = {}
|
103
|
-
end
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
attr_reader :tables, :registry
|
108
|
-
|
109
|
-
public
|
110
|
-
|
111
|
-
def roll_on(table_name)
|
112
|
-
table = @tables.fetch(table_name)
|
113
|
-
table.roll!
|
114
|
-
end
|
115
|
-
|
116
|
-
def add(key, label: key, &block)
|
117
|
-
@tables[key] = Table.new(table_set: self, key: key, label: label, &block)
|
118
|
-
end
|
119
|
-
|
120
|
-
def render(debug: false)
|
121
|
-
puts "Table Set { object_id: #{object_id} }\n" if debug
|
122
|
-
@tables.sort { |a,b| a[0] <=> b[0] }.each do |key, table|
|
123
|
-
table.render
|
124
|
-
end
|
125
|
-
nil
|
126
|
-
end
|
127
|
-
end
|
128
|
-
private_constant :TableSet
|
129
|
-
|
130
|
-
class Table
|
131
|
-
attr_reader :key, :table_set, :label, :roller
|
132
|
-
private :roller
|
133
|
-
def initialize(table_set:, key:, label:, &block)
|
134
|
-
@key = key
|
135
|
-
@table_set = table_set
|
136
|
-
@label = label
|
137
|
-
@range_set = RangeSet.new(table: self)
|
138
|
-
instance_exec(self, &block) if block_given?
|
139
|
-
end
|
140
|
-
|
141
|
-
def render
|
142
|
-
header = "Table: #{key}"
|
143
|
-
header = "#{header} - #{label}" unless label == key
|
144
|
-
puts header
|
145
|
-
puts '-' * header.length
|
146
|
-
roller.render
|
147
|
-
@range_set.render
|
148
|
-
end
|
149
|
-
|
150
|
-
def roll!(the_roller: roller)
|
151
|
-
roll = the_roller.roll!
|
152
|
-
@range_set.resolve(roll: roll)
|
153
|
-
end
|
154
|
-
|
155
|
-
def roll(text)
|
156
|
-
@roller = Roller.new(text)
|
157
|
-
end
|
158
|
-
|
159
|
-
def entry(range, result = nil, roll_on: nil, inner_table: nil, times: 1, &inner_table_config)
|
160
|
-
@range_set.add(
|
161
|
-
table: self,
|
162
|
-
range: range,
|
163
|
-
result: result,
|
164
|
-
roll_on: roll_on,
|
165
|
-
inner_table: inner_table,
|
166
|
-
inner_table_config: inner_table_config,
|
167
|
-
times: times
|
168
|
-
)
|
169
|
-
end
|
170
|
-
|
171
|
-
protected
|
172
|
-
|
173
|
-
class Roller
|
174
|
-
def initialize(text)
|
175
|
-
@text = text
|
176
|
-
end
|
177
|
-
|
178
|
-
def roll!
|
179
|
-
Dice.roll(@text)
|
180
|
-
end
|
181
|
-
|
182
|
-
def render
|
183
|
-
puts "#{@text}\tResult"
|
184
|
-
end
|
185
|
-
end
|
186
|
-
private_constant :Roller
|
187
|
-
|
188
|
-
class RangeSet
|
189
|
-
def initialize(table:)
|
190
|
-
@table = table
|
191
|
-
@ranges = []
|
192
|
-
end
|
193
|
-
|
194
|
-
def render
|
195
|
-
@ranges.sort.each do |range|
|
196
|
-
range.render
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def resolve(roll:)
|
201
|
-
@ranges.detect { |range| range.include?(roll) }.roll!
|
202
|
-
end
|
203
|
-
|
204
|
-
def add(range:, **kwargs)
|
205
|
-
range_object = Range.new(range: range, **kwargs)
|
206
|
-
@ranges << range_object
|
207
|
-
range_object
|
208
|
-
end
|
209
|
-
end
|
210
|
-
private_constant :RangeSet
|
211
|
-
|
212
|
-
module Range
|
213
|
-
def self.new(table:, range:, result:, roll_on:, inner_table:, inner_table_config:, times:)
|
214
|
-
if result
|
215
|
-
Result.new(table: table, range: range, result: result, times: times)
|
216
|
-
elsif roll_on
|
217
|
-
RollOn.new(table: table, range: range, roll_on: roll_on, times: times)
|
218
|
-
elsif inner_table
|
219
|
-
InnerRollOn.new(table: table, range: range, times: times)
|
220
|
-
elsif inner_table_config
|
221
|
-
InnerTable.new(table: table, range: range, inner_table: inner_table_config, times: times)
|
222
|
-
else
|
223
|
-
raise "Hello"
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
class Base
|
228
|
-
attr_reader :table, :range, :times
|
229
|
-
def initialize(table:, range:, times:)
|
230
|
-
@table = table
|
231
|
-
self.range = range
|
232
|
-
@times = times
|
233
|
-
end
|
234
|
-
|
235
|
-
def key
|
236
|
-
"#{table.key} (Sub #{range})"
|
237
|
-
end
|
238
|
-
|
239
|
-
extend Comparable
|
240
|
-
def <=>(other)
|
241
|
-
range.first <=> other.range.first
|
242
|
-
end
|
243
|
-
|
244
|
-
def render
|
245
|
-
if range.first == range.last
|
246
|
-
puts "#{range.first}\t#{result}"
|
247
|
-
else
|
248
|
-
puts "#{range.first}-#{range.last}\t#{result}"
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
def result
|
253
|
-
raise NotImplementedError
|
254
|
-
end
|
255
|
-
|
256
|
-
extend Forwardable
|
257
|
-
def_delegator :table, :table_set
|
258
|
-
|
259
|
-
def include?(value)
|
260
|
-
if @range.respond_to?(:include?)
|
261
|
-
@range.include?(value)
|
262
|
-
else
|
263
|
-
@range == value
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
def range=(input)
|
268
|
-
@range = Array(input)
|
269
|
-
end
|
270
|
-
end
|
271
|
-
private_constant :Base
|
272
|
-
|
273
|
-
class Result < Base
|
274
|
-
attr_reader :result
|
275
|
-
def initialize(result:, **kwargs)
|
276
|
-
super(**kwargs)
|
277
|
-
@result = result
|
278
|
-
end
|
279
|
-
|
280
|
-
def roll!
|
281
|
-
[@result]
|
282
|
-
end
|
283
|
-
end
|
284
|
-
private_constant :Result
|
285
|
-
|
286
|
-
class RollOn < Base
|
287
|
-
def initialize(roll_on:, **kwargs)
|
288
|
-
super(**kwargs)
|
289
|
-
@roll_on = roll_on
|
290
|
-
end
|
291
|
-
|
292
|
-
def roll!
|
293
|
-
(1..times).map { table_set.roll_on(@roll_on) }
|
294
|
-
end
|
295
|
-
|
296
|
-
def result
|
297
|
-
"Roll on #{@roll_on}"
|
298
|
-
end
|
299
|
-
end
|
300
|
-
private_constant :RollOn
|
301
|
-
|
302
|
-
class InnerRollOn < Base
|
303
|
-
def roll!
|
304
|
-
(1..times).map { table_set.roll_on(key) }
|
305
|
-
end
|
306
|
-
|
307
|
-
def result
|
308
|
-
"Roll on #{key}"
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
class InnerTable < Base
|
313
|
-
def initialize(inner_table:, **kwargs)
|
314
|
-
super(**kwargs)
|
315
|
-
@table.table_set.add(key, &inner_table)
|
316
|
-
end
|
317
|
-
|
318
|
-
def roll!
|
319
|
-
(1..times).map { table_set.roll_on(key) }
|
320
|
-
end
|
321
|
-
|
322
|
-
def result
|
323
|
-
"Roll on #{key}"
|
324
|
-
end
|
325
|
-
end
|
326
|
-
private_constant :InnerTable
|
327
|
-
end
|
328
|
-
private_constant :Range
|
329
|
-
end
|
330
|
-
private_constant :Table
|
33
|
+
def_delegator :table_set, :table_names
|
331
34
|
end
|
35
|
+
private_constant :Registry
|
332
36
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'dry-validation'
|
2
|
+
module Rollio
|
3
|
+
module Schemas
|
4
|
+
EntrySchema = Dry::Validation.Schema do
|
5
|
+
required(:range).each(:int?)
|
6
|
+
optional(:result).maybe(:str?)
|
7
|
+
optional(:roll_on).maybe(:str?)
|
8
|
+
optional(:inner_table).schema do
|
9
|
+
required(:roll).filled(:str?)
|
10
|
+
required(:entries).each do
|
11
|
+
schema do
|
12
|
+
required(:range).each(:int?)
|
13
|
+
optional(:result).maybe(:str?)
|
14
|
+
optional(:roll_on).maybe(:str?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
rule :result_or_inner_table_or_rolled_on_is_required do
|
20
|
+
value(:result).filled? ^ value(:roll_on).filled? ^ value(:inner_table).filled?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'dry-validation'
|
2
|
+
require 'rollio/schemas/entry_schema'
|
3
|
+
module Rollio
|
4
|
+
module Schemas
|
5
|
+
TableSchema = Dry::Validation.Schema do
|
6
|
+
required(:key).filled(:str?)
|
7
|
+
required(:roll).filled(:str?)
|
8
|
+
required(:entries).each do
|
9
|
+
schema(EntrySchema)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/rollio/table.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rollio/roller'
|
2
|
+
require 'rollio/range_set'
|
3
|
+
module Rollio
|
4
|
+
class Table
|
5
|
+
attr_reader :key, :table_set, :label, :roller
|
6
|
+
private :roller
|
7
|
+
def initialize(table_set:, key:, label:, &block)
|
8
|
+
@key = key
|
9
|
+
@table_set = table_set
|
10
|
+
@label = label
|
11
|
+
@range_set = RangeSet.new(table: self)
|
12
|
+
instance_exec(self, &block) if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def render
|
16
|
+
header = "Table: #{key}"
|
17
|
+
header = "#{header} - #{label}" unless label == key
|
18
|
+
puts header
|
19
|
+
puts '-' * header.length
|
20
|
+
roller.render
|
21
|
+
@range_set.render
|
22
|
+
end
|
23
|
+
|
24
|
+
def roll!(with: roller)
|
25
|
+
the_roller = with.is_a?(Roller) ? with : Roller.new(with)
|
26
|
+
roll = the_roller.roll!
|
27
|
+
@range_set.resolve(roll: roll)
|
28
|
+
end
|
29
|
+
|
30
|
+
def roll(text)
|
31
|
+
@roller = Roller.new(text)
|
32
|
+
end
|
33
|
+
|
34
|
+
def entry(range, result = nil, **kwargs, &inner_table_config)
|
35
|
+
@range_set.add(
|
36
|
+
table: self,
|
37
|
+
range: range,
|
38
|
+
result: result,
|
39
|
+
inner_table_config: inner_table_config,
|
40
|
+
**kwargs
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
private_constant :Table
|
45
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rollio/table'
|
2
|
+
|
3
|
+
module Rollio
|
4
|
+
# The data store for all of the registered tables
|
5
|
+
class TableSet
|
6
|
+
|
7
|
+
def initialize(registry:)
|
8
|
+
@registry = registry
|
9
|
+
@tables = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :tables, :registry
|
15
|
+
|
16
|
+
public
|
17
|
+
|
18
|
+
def table_names
|
19
|
+
tables.keys.sort
|
20
|
+
end
|
21
|
+
|
22
|
+
def roll_on(table_name, **kwargs)
|
23
|
+
table = tables.fetch(table_name)
|
24
|
+
table.roll!(**kwargs)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(key, label: key, &block)
|
28
|
+
tables[key] = Table.new(table_set: self, key: key, label: label, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def render(debug: false)
|
32
|
+
puts "Table Set { object_id: #{object_id} }\n" if debug
|
33
|
+
tables.sort { |a,b| a[0] <=> b[0] }.each do |key, table|
|
34
|
+
table.render
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
private_constant :TableSet
|
40
|
+
end
|
data/lib/rollio/version.rb
CHANGED
data/rollio.gemspec
CHANGED
@@ -27,4 +27,8 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
29
|
spec.add_dependency "dice_parser"
|
30
|
+
spec.add_dependency "dry-validation"
|
31
|
+
spec.add_dependency "json"
|
32
|
+
spec.add_dependency "hanami-utils"
|
33
|
+
spec.add_dependency "thor"
|
30
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rollio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Friesen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,10 +66,67 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: dry-validation
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: hanami-utils
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: thor
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
69
125
|
description: A DSL and JSON Schema for RPG tables
|
70
126
|
email:
|
71
127
|
- jeremy.n.friesen@gmail.com
|
72
|
-
executables:
|
128
|
+
executables:
|
129
|
+
- rollio
|
73
130
|
extensions: []
|
74
131
|
extra_rdoc_files: []
|
75
132
|
files:
|
@@ -83,8 +140,19 @@ files:
|
|
83
140
|
- Rakefile
|
84
141
|
- bin/console
|
85
142
|
- bin/setup
|
143
|
+
- data/defy_danger.json
|
144
|
+
- data/examples.json
|
145
|
+
- exe/rollio
|
86
146
|
- lib/rollio.rb
|
147
|
+
- lib/rollio/cli.rb
|
148
|
+
- lib/rollio/range.rb
|
149
|
+
- lib/rollio/range_set.rb
|
87
150
|
- lib/rollio/registry.rb
|
151
|
+
- lib/rollio/roller.rb
|
152
|
+
- lib/rollio/schemas/entry_schema.rb
|
153
|
+
- lib/rollio/schemas/table_schema.rb
|
154
|
+
- lib/rollio/table.rb
|
155
|
+
- lib/rollio/table_set.rb
|
88
156
|
- lib/rollio/version.rb
|
89
157
|
- rollio.gemspec
|
90
158
|
homepage: https://github.com/jeremyf/rollio
|