calyx 0.5.1 → 0.6.0
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/.travis.yml +0 -1
- data/README.md +128 -0
- data/lib/calyx.rb +59 -21
- data/lib/calyx/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f131c3c4d9ce8acaa598a0f6e32b92f13da5c566
|
4
|
+
data.tar.gz: c4e81bf0f753c605946c77c4943c28f1358632b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12a3d0964f80866aae48ae67036b6e97afb1ef3d89ca005bfbcbd6a8df7f55d2400cb8774ded7f2fbefd6b64b0e8da3b9201ade2c3599670918a2fba0f9c6f29
|
7
|
+
data.tar.gz: 6bd0062c621e001f28322484dd4dd7f9762a5e12de07fbbe26500a1b9fd03655099b22ec036046c96163b479f381c37be5fb711e5eacb9efd511a983538e982e
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Calyx
|
2
2
|
|
3
|
+
[](https://rubygems.org/gems/calyx)
|
4
|
+
[](https://travis-ci.org/maetl/calyx)
|
5
|
+
|
3
6
|
Calyx provides a simple API for generating text with declarative recursive grammars.
|
4
7
|
|
5
8
|
## Install
|
@@ -56,6 +59,21 @@ hello.generate
|
|
56
59
|
# > "Yo world."
|
57
60
|
```
|
58
61
|
|
62
|
+
### Block Constructors
|
63
|
+
|
64
|
+
As an alternative to subclassing, you can also construct rules unique to an instance by passing a block when initializing the class:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
hello = Calyx::Grammar.new do
|
68
|
+
start '{greeting} world.'
|
69
|
+
rule :greeting, 'Hello', 'Hi', 'Hey', 'Yo'
|
70
|
+
end
|
71
|
+
|
72
|
+
hello.generate
|
73
|
+
```
|
74
|
+
|
75
|
+
### Nesting and Substitution
|
76
|
+
|
59
77
|
Rules are recursive. They can be arbitrarily nested and connected to generate larger and more complex texts.
|
60
78
|
|
61
79
|
```ruby
|
@@ -90,6 +108,116 @@ module HelloWorld
|
|
90
108
|
end
|
91
109
|
```
|
92
110
|
|
111
|
+
### Random Sampling
|
112
|
+
|
113
|
+
By default, the outcomes of generated rules are selected with Ruby’s built-in random number generator (as seen in methods like `Kernel.rand` and `Array.sample`). If you want to supply a weighted probability list, you can pass in arrays to the rule constructor, with the first argument being the template text string and the second argument being a float representing the probability between `0` and `1` of this choice being selected.
|
114
|
+
|
115
|
+
For example, you can model the triangular distribution produced by rolling 2d6:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
class Roll2D6 < Calyx::Grammar
|
119
|
+
start(
|
120
|
+
['2', 0.0278],
|
121
|
+
['3', 0.556],
|
122
|
+
['4', 0.833],
|
123
|
+
['5', 0.1111],
|
124
|
+
['6', 0.1389],
|
125
|
+
['7', 0.1667],
|
126
|
+
['8', 0.1389],
|
127
|
+
['9', 0.1111],
|
128
|
+
['10', 0.833],
|
129
|
+
['11', 0.556],
|
130
|
+
['12', 0.278]
|
131
|
+
)
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
Or reproduce Gary Gygax’s famous generation table from the original Dungeon Master’s Guide (page 171):
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
class ChamberOrRoomContents < Calyx::Grammar
|
139
|
+
start(
|
140
|
+
[:empty, 0.6],
|
141
|
+
[:monster, 0.1],
|
142
|
+
[:monster_treasure, 0.15],
|
143
|
+
[:special, 0.05],
|
144
|
+
[:trick_trap, 0.05],
|
145
|
+
[:treasure, 0.05]
|
146
|
+
)
|
147
|
+
|
148
|
+
rule :empty, 'Empty'
|
149
|
+
rule :monster, 'Monster Only'
|
150
|
+
rule :monster_treasure, 'Monster and Treasure'
|
151
|
+
rule :special, 'Special'
|
152
|
+
rule :trick_trap, 'Trick/Trap.'
|
153
|
+
rule :treasure, 'Treasure'
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
### Template Expressions
|
158
|
+
|
159
|
+
Basic rule substitution uses single curly brackets as delimiters for template expressions:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
class Fruit < Calyx::Grammar
|
163
|
+
start '{colour} {fruit}'
|
164
|
+
rule :colour, 'red', 'green', 'yellow'
|
165
|
+
rule :fruit, 'apple', 'pear', 'tomato'
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
Dot-notation is supported in template expressions, allowing you to call any available method on the `String` object returned from a rule. Formatting methods can be chained arbitrarily and will execute in the same way as they would in native Ruby code.
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class Greeting < Calyx::Grammar
|
173
|
+
start '{hello.capitalize} there.', 'Why, {hello} there.'
|
174
|
+
rule :hello, 'hello'
|
175
|
+
end
|
176
|
+
|
177
|
+
# => "Hello there."
|
178
|
+
# => "Why, hello there."
|
179
|
+
```
|
180
|
+
|
181
|
+
In order to use more intricate natural language processing capabilities, you can embed additional methods onto the `String` class yourself, as well as use methods from existing Gems that monkeypatch `String`.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
require 'indefinite_article'
|
185
|
+
|
186
|
+
module FullStop
|
187
|
+
def full_stop
|
188
|
+
self << '.'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class String
|
193
|
+
include FullStop
|
194
|
+
end
|
195
|
+
|
196
|
+
class NounsWithArticles < Calyx::Grammar
|
197
|
+
start '{fruit.with_indefinite_article.capitalize.full_stop}'
|
198
|
+
rule :fruit, 'apple', 'orange', 'banana', 'pear'
|
199
|
+
end
|
200
|
+
|
201
|
+
# => "An apple."
|
202
|
+
# => "An orange."
|
203
|
+
# => "A banana."
|
204
|
+
# => "A pear."
|
205
|
+
```
|
206
|
+
|
207
|
+
## Roadmap
|
208
|
+
|
209
|
+
Rough plan for stabilising the API and features for a `1.0` release.
|
210
|
+
|
211
|
+
| Version | Features planned |
|
212
|
+
|---------|------------------|
|
213
|
+
| `0.6` | block constructor |
|
214
|
+
| `0.7` | support for template context map passed to generate |
|
215
|
+
| `0.8` | return grammar tree from evaluate/generate, with to_s being separate |
|
216
|
+
| `0.9` | support mixin/composition of rule sets rather than inheritance |
|
217
|
+
| `0.10` | support YAML format (and JSON?) |
|
218
|
+
| `0.11` | method missing metaclass API |
|
219
|
+
| `1.0` | API documentation |
|
220
|
+
|
93
221
|
## License
|
94
222
|
|
95
223
|
Calyx is open source and provided under the terms of the MIT license. Copyright (c) 2015 Mark Rickerby
|
data/lib/calyx.rb
CHANGED
@@ -1,34 +1,67 @@
|
|
1
1
|
module Calyx
|
2
2
|
class Grammar
|
3
|
-
class
|
4
|
-
|
3
|
+
class Registry
|
4
|
+
def initialize
|
5
|
+
@rules = {}
|
6
|
+
end
|
5
7
|
|
6
8
|
def start(*productions, &production)
|
7
|
-
|
9
|
+
@rules[:start] = construct_rule(productions)
|
8
10
|
end
|
9
11
|
|
10
12
|
def rule(name, *productions, &production)
|
11
|
-
|
13
|
+
@rules[name.to_sym] = construct_rule(productions)
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
@
|
16
|
-
@registry.merge!(rules || {})
|
16
|
+
def []=(symbol, production)
|
17
|
+
@rules[symbol] = production
|
17
18
|
end
|
18
19
|
|
19
|
-
def
|
20
|
-
|
20
|
+
def [](symbol)
|
21
|
+
@rules[symbol]
|
22
|
+
end
|
23
|
+
|
24
|
+
def combine(rules)
|
25
|
+
@rules.merge!(rules.to_h)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_h
|
29
|
+
@rules
|
21
30
|
end
|
22
31
|
|
32
|
+
private
|
33
|
+
|
23
34
|
def construct_rule(productions)
|
24
35
|
if productions.first.is_a?(Enumerable)
|
25
|
-
Production::WeightedChoices.parse(productions,
|
36
|
+
Production::WeightedChoices.parse(productions, self)
|
26
37
|
else
|
27
|
-
Production::Choices.parse(productions,
|
38
|
+
Production::Choices.parse(productions, self)
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
31
42
|
|
43
|
+
class << self
|
44
|
+
def registry
|
45
|
+
@registry ||= Registry.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def start(*productions, &production)
|
49
|
+
registry.start(*productions)
|
50
|
+
end
|
51
|
+
|
52
|
+
def rule(name, *productions, &production)
|
53
|
+
registry.rule(name, *productions)
|
54
|
+
end
|
55
|
+
|
56
|
+
def inherit_registry(rules)
|
57
|
+
registry.combine(rules) unless rules.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
def inherited(subclass)
|
61
|
+
subclass.inherit_registry(registry)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
32
65
|
module Production
|
33
66
|
class NonTerminal
|
34
67
|
def initialize(expansion, registry)
|
@@ -65,14 +98,16 @@ module Calyx
|
|
65
98
|
end
|
66
99
|
|
67
100
|
class Concat
|
68
|
-
|
69
|
-
|
101
|
+
EXPRESSION = /(\{[A-Za-z0-9_\.]+\})/.freeze
|
102
|
+
START_TOKEN = '{'.freeze
|
103
|
+
END_TOKEN = '}'.freeze
|
104
|
+
DEREF_TOKEN = '.'.freeze
|
70
105
|
|
71
106
|
def self.parse(production, registry)
|
72
|
-
expansion = production.split(
|
107
|
+
expansion = production.split(EXPRESSION).map do |atom|
|
73
108
|
if atom.is_a?(String)
|
74
|
-
if atom.chars.first ==
|
75
|
-
head, *tail = atom.slice(1, atom.length-2).split(
|
109
|
+
if atom.chars.first == START_TOKEN && atom.chars.last == END_TOKEN
|
110
|
+
head, *tail = atom.slice(1, atom.length-2).split(DEREF_TOKEN)
|
76
111
|
rule = NonTerminal.new(head, registry)
|
77
112
|
unless tail.empty?
|
78
113
|
Expression.new(rule, tail)
|
@@ -155,18 +190,21 @@ module Calyx
|
|
155
190
|
end
|
156
191
|
end
|
157
192
|
|
158
|
-
def initialize(seed=nil)
|
193
|
+
def initialize(seed=nil, &block)
|
159
194
|
@seed = seed
|
160
195
|
@seed = Time.new.to_i unless @seed
|
161
196
|
srand(@seed)
|
162
|
-
end
|
163
197
|
|
164
|
-
|
165
|
-
|
198
|
+
if block_given?
|
199
|
+
@registry = Registry.new
|
200
|
+
@registry.instance_eval(&block)
|
201
|
+
else
|
202
|
+
@registry = self.class.registry
|
203
|
+
end
|
166
204
|
end
|
167
205
|
|
168
206
|
def generate
|
169
|
-
registry[:start].evaluate
|
207
|
+
@registry[:start].evaluate
|
170
208
|
end
|
171
209
|
end
|
172
210
|
end
|
data/lib/calyx/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calyx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Rickerby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,3 +94,4 @@ signing_key:
|
|
94
94
|
specification_version: 4
|
95
95
|
summary: Generate text with declarative recursive grammars
|
96
96
|
test_files: []
|
97
|
+
has_rdoc:
|