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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c0d95f945e56c8dd61240e8868b62dfae5f4ac3
4
- data.tar.gz: 4ced529a55be7f48c54875caa37b896ae40bdc2c
3
+ metadata.gz: f131c3c4d9ce8acaa598a0f6e32b92f13da5c566
4
+ data.tar.gz: c4e81bf0f753c605946c77c4943c28f1358632b2
5
5
  SHA512:
6
- metadata.gz: 52ce90165a9e98c61f3a32849ef53d18af8c23772e5c31025a40c9edc6e3482ea896d188d56fd091485af6d22eb79fb2b58cd48096ec4c900ee802eb3402afac
7
- data.tar.gz: d25eba6f569b69261d6eb77caeae011febfbc3177e29fb66614cc6721f799dcdd0237ead1190d87fd0ae25d8df095a754a07f948a9772a931554a5a1bb4a4f88
6
+ metadata.gz: 12a3d0964f80866aae48ae67036b6e97afb1ef3d89ca005bfbcbd6a8df7f55d2400cb8774ded7f2fbefd6b64b0e8da3b9201ade2c3599670918a2fba0f9c6f29
7
+ data.tar.gz: 6bd0062c621e001f28322484dd4dd7f9762a5e12de07fbbe26500a1b9fd03655099b22ec036046c96163b479f381c37be5fb711e5eacb9efd511a983538e982e
data/.travis.yml CHANGED
@@ -4,7 +4,6 @@ rvm:
4
4
  - 2.2
5
5
  - rbx-2
6
6
  - jruby-9
7
- - ruby-head
8
7
  - jruby-head
9
8
  before_install: gem install bundler -v 1.10.6
10
9
  script: bundle exec rspec
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Calyx
2
2
 
3
+ [![Gem Version](http://img.shields.io/gem/v/yarrow.svg)](https://rubygems.org/gems/calyx)
4
+ [![Build Status](https://travis-ci.org/maetl/calyx.svg?branch=master)](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 << self
4
- attr_accessor :registry
3
+ class Registry
4
+ def initialize
5
+ @rules = {}
6
+ end
5
7
 
6
8
  def start(*productions, &production)
7
- registry[:start] = construct_rule(productions)
9
+ @rules[:start] = construct_rule(productions)
8
10
  end
9
11
 
10
12
  def rule(name, *productions, &production)
11
- registry[name.to_sym] = construct_rule(productions)
13
+ @rules[name.to_sym] = construct_rule(productions)
12
14
  end
13
15
 
14
- def inherit_registry(rules)
15
- @registry ||= {}
16
- @registry.merge!(rules || {})
16
+ def []=(symbol, production)
17
+ @rules[symbol] = production
17
18
  end
18
19
 
19
- def inherited(subclass)
20
- subclass.inherit_registry(@registry)
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, registry)
36
+ Production::WeightedChoices.parse(productions, self)
26
37
  else
27
- Production::Choices.parse(productions, registry)
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
- DELIMITER = /(\{[A-Za-z0-9_\.]+\})/.freeze
69
- DEREF = '.'.freeze
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(DELIMITER).map do |atom|
107
+ expansion = production.split(EXPRESSION).map do |atom|
73
108
  if atom.is_a?(String)
74
- if atom.chars.first == '{' && atom.chars.last == '}'
75
- head, *tail = atom.slice(1, atom.length-2).split(DEREF)
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
- def registry
165
- self.class.registry
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
@@ -1,3 +1,3 @@
1
1
  module Calyx
2
- VERSION = '0.5.1'.freeze
2
+ VERSION = '0.6.0'.freeze
3
3
  end
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.5.1
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: 2015-11-28 00:00:00.000000000 Z
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: