rollio 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|