story-gen 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS CHANGED
@@ -1,3 +1,6 @@
1
+ 0.1.7
2
+ Bug fixes, extract Parse into separate gem
3
+
1
4
  0.1.5:
2
5
  Add "once" and "UniqueNames.delete"
3
6
 
@@ -5,6 +5,11 @@ class Array
5
5
  #
6
6
  # @return [self]
7
7
  #
8
+ # @example
9
+ #
10
+ # [1, 2, 3].chomp!(3) #=> [1, 2]
11
+ # [1, 2, 3].chomp!(2) #=> [1, 2, 3]
12
+ #
8
13
  def chomp!(item)
9
14
  self.pop if item == self.last
10
15
  return self
@@ -16,6 +21,3 @@ class Array
16
21
  end
17
22
 
18
23
  end
19
-
20
- # p [1, 2, 3].chomp(3)
21
- # p [1, 2, 3].chomp(2)
@@ -1,9 +1,13 @@
1
1
 
2
- class Array
2
+ unless Array.method_defined? :to_h
3
3
 
4
- # @return [Hash]
5
- def to_h
6
- self.reduce({}) { |h, e| h[e.first] = e.last; h }
4
+ class Array
5
+
6
+ # @return [Hash]
7
+ def to_h
8
+ self.reduce({}) { |h, e| h[e.first] = e.last; h }
9
+ end
10
+
7
11
  end
8
12
 
9
13
  end
@@ -0,0 +1,11 @@
1
+
2
+ class Integer
3
+
4
+ # @return [Array] an {Array} of n results of call to +block+, where n is self.
5
+ def of(&block)
6
+ r = []
7
+ self.times { r.push(block.()) }
8
+ return r;
9
+ end
10
+
11
+ end
@@ -0,0 +1,237 @@
1
+ # encoding: UTF-8
2
+
3
+ class Names
4
+
5
+ # @return [Array<String>]
6
+ def self.russian_male
7
+ %W{
8
+ Адам
9
+ Адриан
10
+ Александр
11
+ Алексей
12
+ Анатолий
13
+ Андрей
14
+ Антон
15
+ Аркадий
16
+ Арсений
17
+ Артем
18
+ Артур
19
+
20
+ Богдан
21
+ Борис
22
+
23
+ Вадим
24
+ Валентин
25
+ Валерий
26
+ Василий
27
+ Виктор
28
+ Виталий
29
+ Владимир
30
+ Владислав
31
+ Вячеслав
32
+
33
+ Геннадий
34
+ Георгий
35
+ Герман
36
+ Глеб
37
+ Григорий
38
+
39
+ Давид
40
+ Даниил
41
+ Денис
42
+ Дмитрий
43
+
44
+ Евгений
45
+ Егор
46
+ Ефим
47
+
48
+ Захар
49
+
50
+ Иван
51
+ Игорь
52
+ Илья
53
+
54
+ Кирилл
55
+ Константин
56
+
57
+ Лев
58
+ Леонид
59
+
60
+ Максим
61
+ Марк
62
+ Матвей
63
+ Мирослав
64
+ Михаил
65
+
66
+ Назар
67
+ Нестор
68
+ Никита
69
+ Николай
70
+
71
+ Олег
72
+ Орест
73
+ Оскар
74
+ Остап
75
+
76
+ Павел
77
+ Петр
78
+ Платон
79
+
80
+ Ренат
81
+ Родион
82
+ Роман
83
+ Ростислав
84
+ Руслан
85
+
86
+ Святослав
87
+ Семен
88
+ Сергей
89
+ Станислав
90
+ Степан
91
+
92
+ Тарас
93
+ Тимофей
94
+ Тимур
95
+
96
+ Федор
97
+ Филипп
98
+
99
+ Эдуард
100
+
101
+ Юрий
102
+
103
+ Яков
104
+ Ян
105
+ Ярослав
106
+ }
107
+ end
108
+
109
+ # @return [Array<String>]
110
+ def self.russian_female
111
+ %W{
112
+ Агата
113
+ Ада
114
+ Адель
115
+ Адриана
116
+ Алевтина
117
+ Александра
118
+ Алина
119
+ Алиса
120
+ Алла
121
+ Альбина
122
+ Анастасия
123
+ Ангелина
124
+ Анжела
125
+ Анна
126
+ Антонина
127
+ Анфиса
128
+ Арина
129
+
130
+ Богдана
131
+ Борислава
132
+
133
+ Валентина
134
+ Валерия
135
+ Варвара
136
+ Василиса
137
+ Вера
138
+ Вероника
139
+ Виктория
140
+ Виолетта
141
+
142
+ Галина
143
+
144
+ Дарья
145
+ Диана
146
+
147
+ Ева
148
+ Евгения
149
+ Екатерина
150
+ Елена
151
+ Елизавета
152
+
153
+ Жанна
154
+
155
+ Зинаида
156
+ Зоя
157
+
158
+ Илона
159
+ Инга
160
+ Инесса
161
+ Инна
162
+ Ирина
163
+
164
+ Карина
165
+ Кира
166
+ Клавдия
167
+ Клара
168
+ Кристина
169
+ Ксения
170
+
171
+ Лариса
172
+ Лидия
173
+ Лилия
174
+ Любовь
175
+ Людмила
176
+
177
+ Майя
178
+ Маргарита
179
+ Марина
180
+ Мария
181
+ Марта
182
+ Марьяна
183
+ Мирослава
184
+
185
+ Надежда
186
+ Наталья
187
+ Нелли
188
+ Нина
189
+
190
+ Оксана
191
+ Ольга
192
+
193
+ Полина
194
+
195
+ Раиса
196
+ Регина
197
+ Римма
198
+ Роза
199
+ Роксана
200
+ Руслана
201
+
202
+ Светлана
203
+ Снежана
204
+ София
205
+
206
+ Таисия
207
+ Тамара
208
+ Татьяна
209
+
210
+ Ульяна
211
+
212
+ Христина
213
+
214
+ Эвелина
215
+ Элеонора
216
+ Эльвира
217
+ Эмма
218
+
219
+ Юлиана
220
+ Юлия
221
+
222
+ Яна
223
+ Ярослава
224
+ }
225
+ end
226
+
227
+ # @return [Array<String>]
228
+ def self.english_male
229
+ ["Jack", "Thomas", "Joshua", "Oliver", "Harry", "James", "Charlie", "William", "Daniel", "Samuel", "Alfie", "Benjamin", "Joseph", "George", "Callum", "Jake", "Ethan", "Lewis", "Luke", "Mohammed", "Matthew", "Dylan", "Jacob", "Alexander", "Ryan", "Adam", "Tyler", "Harvey", "Liam", "Max", "Cameron", "Harrison", "Jamie", "Jayden", "Leo", "Owen", "Henry", "Connor", "Archie", "Nathan", "Ben", "Muhammad", "Oscar", "Edward", "Lucas", "Michael", "Isaac", "Aaron", "Kyle", "Noah", "Finley", "Rhys", "Bradley", "Charles", "Toby", "Louis", "Brandon", "Logan", "Mason", "Reece", "Kieran", "Alex", "Riley", "Finlay", "Kai", "Freddie", "David", "Harley", "Kian", "Mohammad", "Bailey", "Sam", "Luca", "Joel", "Theo", "Leon", "John", "Robert", "Ashton", "Ellis", "Joe", "Aidan", "Billy", "Corey", "Hayden", "Evan", "Zachary", "Taylor", "Christopher", "Sebastian", "Elliot", "Morgan", "Jay", "Dominic", "Reuben", "Gabriel", "Sean", "Louie", "Andrew", "Frederick", "Ewan", "Zak"]
230
+ end
231
+
232
+ # @return [Array<String>]
233
+ def self.english_female
234
+ ["Olivia", "Grace", "Ruby", "Jessica", "Emily", "Sophie", "Chloe", "Lucy", "Lily", "Ella", "Ellie", "Amelia", "Charlotte", "Katie", "Mia", "Hannah", "Evie", "Megan", "Amy", "Isabella", "Millie", "Isabelle", "Abigail", "Freya", "Molly", "Daisy", "Holly", "Emma", "Erin", "Poppy", "Jasmine", "Phoebe", "Leah", "Keira", "Caitlin", "Imogen", "Madison", "Rebecca", "Elizabeth", "Georgia", "Sophia", "Lauren", "Scarlett", "Amber", "Ava", "Eleanor", "Bethany", "Alice", "Isabel", "Summer", "Paige", "Anna", "Lola", "Libby", "Eva", "Maisie", "Isobel", "Brooke", "Lilly", "Alisha", "Tia", "Sarah", "Amelie", "Gracie", "Faith", "Rosie", "Courtney", "Matilda", "Niamh", "Maddison", "Sienna", "Eve", "Aimee", "Skye", "Zara", "Isla", "Shannon", "Madeleine", "Harriet", "Zoe", "Nicole", "Sofia", "Abbie", "Maya", "Lacey", "Rachel", "Francesca", "Layla", "Lydia", "Alicia", "Hollie", "Martha", "Alexandra", "Julia", "Natasha", "Lexie", "Mollie", "Morgan", "Maria", "Demi", "Rose", "Laura", "Lara", "Victoria", "Tilly", "Sara", "Evelyn", "Eloise"]
235
+ end
236
+
237
+ end
@@ -53,7 +53,6 @@ class Story
53
53
  #
54
54
  c = code <<
55
55
  "require 'enumerable/empty'\n"<<
56
- "require 'enumerable/lazy'\n"<<
57
56
  "require 'set'\n"<<
58
57
  "require 'story'\n"<<
59
58
  "require 'enumerable/new'\n"<<
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  require 'set'
3
3
  require 'once'
4
+ require 'names'
4
5
 
5
6
  # Infinite set of unique names.
6
7
  class UniqueNames
@@ -11,239 +12,27 @@ class UniqueNames
11
12
  @base_names = base_names
12
13
  @postfix_id = 0
13
14
  @deleted_names = Set.new
14
- reinit_current_names()
15
+ reinit_current_names
15
16
  end
16
17
 
17
18
  # @return [UniqueNames]
18
19
  def self.russian_male
19
- UniqueNames.new %W{
20
- Адам
21
- Адриан
22
- Александр
23
- Алексей
24
- Анатолий
25
- Андрей
26
- Антон
27
- Аркадий
28
- Арсений
29
- Артем
30
- Артур
31
-
32
- Богдан
33
- Борис
34
-
35
- Вадим
36
- Валентин
37
- Валерий
38
- Василий
39
- Виктор
40
- Виталий
41
- Владимир
42
- Владислав
43
- Вячеслав
44
-
45
- Геннадий
46
- Георгий
47
- Герман
48
- Глеб
49
- Григорий
50
-
51
- Давид
52
- Даниил
53
- Денис
54
- Дмитрий
55
-
56
- Евгений
57
- Егор
58
- Ефим
59
-
60
- Захар
61
-
62
- Иван
63
- Игорь
64
- Илья
65
-
66
- Кирилл
67
- Константин
68
-
69
- Лев
70
- Леонид
71
-
72
- Максим
73
- Марк
74
- Матвей
75
- Мирослав
76
- Михаил
77
-
78
- Назар
79
- Нестор
80
- Никита
81
- Николай
82
-
83
- Олег
84
- Орест
85
- Оскар
86
- Остап
87
-
88
- Павел
89
- Петр
90
- Платон
91
-
92
- Ренат
93
- Родион
94
- Роман
95
- Ростислав
96
- Руслан
97
-
98
- Святослав
99
- Семен
100
- Сергей
101
- Станислав
102
- Степан
103
-
104
- Тарас
105
- Тимофей
106
- Тимур
107
-
108
- Федор
109
- Филипп
110
-
111
- Эдуард
112
-
113
- Юрий
114
-
115
- Яков
116
- Ян
117
- Ярослав
118
- }
20
+ UniqueNames.new(Names.russian_male)
119
21
  end
120
22
 
121
23
  # @return [UniqueNames]
122
24
  def self.russian_female
123
- UniqueNames.new %W{
124
- Агата
125
- Ада
126
- Адель
127
- Адриана
128
- Алевтина
129
- Александра
130
- Алина
131
- Алиса
132
- Алла
133
- Альбина
134
- Анастасия
135
- Ангелина
136
- Анжела
137
- Анна
138
- Антонина
139
- Анфиса
140
- Арина
141
-
142
- Богдана
143
- Борислава
144
-
145
- Валентина
146
- Валерия
147
- Варвара
148
- Василиса
149
- Вера
150
- Вероника
151
- Виктория
152
- Виолетта
153
-
154
- Галина
155
-
156
- Дарья
157
- Диана
158
-
159
- Ева
160
- Евгения
161
- Екатерина
162
- Елена
163
- Елизавета
164
-
165
- Жанна
166
-
167
- Зинаида
168
- Зоя
169
-
170
- Илона
171
- Инга
172
- Инесса
173
- Инна
174
- Ирина
175
-
176
- Карина
177
- Кира
178
- Клавдия
179
- Клара
180
- Кристина
181
- Ксения
182
-
183
- Лариса
184
- Лидия
185
- Лилия
186
- Любовь
187
- Людмила
188
-
189
- Майя
190
- Маргарита
191
- Марина
192
- Мария
193
- Марта
194
- Марьяна
195
- Мирослава
196
-
197
- Надежда
198
- Наталья
199
- Нелли
200
- Нина
201
-
202
- Оксана
203
- Ольга
204
-
205
- Полина
206
-
207
- Раиса
208
- Регина
209
- Римма
210
- Роза
211
- Роксана
212
- Руслана
213
-
214
- Светлана
215
- Снежана
216
- София
217
-
218
- Таисия
219
- Тамара
220
- Татьяна
221
-
222
- Ульяна
223
-
224
- Христина
225
-
226
- Эвелина
227
- Элеонора
228
- Эльвира
229
- Эмма
230
-
231
- Юлиана
232
- Юлия
233
-
234
- Яна
235
- Ярослава
236
- }
25
+ UniqueNames.new(Names.russian_female)
237
26
  end
238
27
 
239
28
  # @return [UniqueNames]
240
29
  def self.english_male
241
- UniqueNames.new ["Jack", "Thomas", "Joshua", "Oliver", "Harry", "James", "Charlie", "William", "Daniel", "Samuel", "Alfie", "Benjamin", "Joseph", "George", "Callum", "Jake", "Ethan", "Lewis", "Luke", "Mohammed", "Matthew", "Dylan", "Jacob", "Alexander", "Ryan", "Adam", "Tyler", "Harvey", "Liam", "Max", "Cameron", "Harrison", "Jamie", "Jayden", "Leo", "Owen", "Henry", "Connor", "Archie", "Nathan", "Ben", "Muhammad", "Oscar", "Edward", "Lucas", "Michael", "Isaac", "Aaron", "Kyle", "Noah", "Finley", "Rhys", "Bradley", "Charles", "Toby", "Louis", "Brandon", "Logan", "Mason", "Reece", "Kieran", "Alex", "Riley", "Finlay", "Kai", "Freddie", "David", "Harley", "Kian", "Mohammad", "Bailey", "Sam", "Luca", "Joel", "Theo", "Leon", "John", "Robert", "Ashton", "Ellis", "Joe", "Aidan", "Billy", "Corey", "Hayden", "Evan", "Zachary", "Taylor", "Christopher", "Sebastian", "Elliot", "Morgan", "Jay", "Dominic", "Reuben", "Gabriel", "Sean", "Louie", "Andrew", "Frederick", "Ewan", "Zak"]
30
+ UniqueNames.new(Names.english_male)
242
31
  end
243
32
 
244
33
  # @return [UniqueNames]
245
34
  def self.english_female
246
- UniqueNames.new ["Olivia", "Grace", "Ruby", "Jessica", "Emily", "Sophie", "Chloe", "Lucy", "Lily", "Ella", "Ellie", "Amelia", "Charlotte", "Katie", "Mia", "Hannah", "Evie", "Megan", "Amy", "Isabella", "Millie", "Isabelle", "Abigail", "Freya", "Molly", "Daisy", "Holly", "Emma", "Erin", "Poppy", "Jasmine", "Phoebe", "Leah", "Keira", "Caitlin", "Imogen", "Madison", "Rebecca", "Elizabeth", "Georgia", "Sophia", "Lauren", "Scarlett", "Amber", "Ava", "Eleanor", "Bethany", "Alice", "Isabel", "Summer", "Paige", "Anna", "Lola", "Libby", "Eva", "Maisie", "Isobel", "Brooke", "Lilly", "Alisha", "Tia", "Sarah", "Amelie", "Gracie", "Faith", "Rosie", "Courtney", "Matilda", "Niamh", "Maddison", "Sienna", "Eve", "Aimee", "Skye", "Zara", "Isla", "Shannon", "Madeleine", "Harriet", "Zoe", "Nicole", "Sofia", "Abbie", "Maya", "Lacey", "Rachel", "Francesca", "Layla", "Lydia", "Alicia", "Hollie", "Martha", "Alexandra", "Julia", "Natasha", "Lexie", "Mollie", "Morgan", "Maria", "Demi", "Rose", "Laura", "Lara", "Victoria", "Tilly", "Sara", "Evelyn", "Eloise"]
35
+ UniqueNames.new(Names.english_female)
247
36
  end
248
37
 
249
38
  # @param [String] name
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: story-gen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-02-28 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2016-05-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: parse-framework
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: Generate stories from descriptions based on Facts!
15
31
  email: various.furriness@gmail.com
16
32
  executables:
@@ -19,11 +35,12 @@ extensions: []
19
35
  extra_rdoc_files: []
20
36
  files:
21
37
  - lib/once.rb
22
- - lib/strscan/substr.rb
23
38
  - lib/any.rb
39
+ - lib/integer/of.rb
24
40
  - lib/fact.rb
25
41
  - lib/story/compile.rb
26
42
  - lib/story/samples_dir.rb
43
+ - lib/names.rb
27
44
  - lib/array/case_equal_fixed.rb
28
45
  - lib/array/separate.rb
29
46
  - lib/array/to_h.rb
@@ -31,14 +48,12 @@ files:
31
48
  - lib/string/ru_downcase.rb
32
49
  - lib/string/lchomp.rb
33
50
  - lib/story.rb
34
- - lib/parse.rb
35
51
  - lib/enumerable/empty.rb
36
52
  - lib/enumerable/lazy.rb
37
53
  - lib/enumerable/new.rb
38
54
  - lib/enumerable/sample.rb
39
55
  - lib/hash/put.rb
40
56
  - lib/unique_names.rb
41
- - lib/code.rb
42
57
  - lib/object/map_.rb
43
58
  - lib/object/to_rb.rb
44
59
  - README.md
@@ -1,138 +0,0 @@
1
-
2
- class Code
3
-
4
- # @api private
5
- # @note used by {Code}, {::code}, {::non_code} only.
6
- #
7
- # @param [Array<String, NonCodePart>] parts
8
- # @param [Object, nil] metadata
9
- #
10
- def initialize(parts, metadata = nil)
11
- @parts = parts
12
- @metadata = metadata
13
- end
14
-
15
- # @overload + str
16
- # @param [String] str
17
- # @return [Code]
18
- # @overload + code
19
- # @param [Code] code
20
- # @return [Code]
21
- def + arg
22
- case arg
23
- when String then self + Code.new([arg])
24
- when Code then Code.new(self.parts + arg.parts)
25
- end
26
- end
27
-
28
- # @overload << str
29
- # Appends +str+ to self.
30
- # @param [String] str
31
- # @return [self]
32
- # @overload << code
33
- # Appends +str+ to self.
34
- # @param [Code] code
35
- # @return [self]
36
- def << arg
37
- case arg
38
- when String then self << Code.new([arg])
39
- when Code then @parts.concat(arg.parts); self
40
- end
41
- end
42
-
43
- # @overload metadata(obj)
44
- # @param [Object] obj
45
- # @return [Code] a {Code} with +obj+ attached to it. The +obj+ can later
46
- # be retrieved with {#metadata}().
47
- # @overload metadata
48
- # @return [Object, nil] an {Object} attached to this {Code} with
49
- # {#metadata}(obj) or nil if no {Object} is attached.
50
- def metadata(*args)
51
- if args.empty?
52
- then @metadata
53
- else Code.new(@parts, args.first)
54
- end
55
- end
56
-
57
- # @yieldparam [Object] part
58
- # @yieldreturn [String]
59
- # @return [Code] a {Code} with {#non_code_parts} mapped by the passed block.
60
- def map_non_code_parts(&f)
61
- Code.new(
62
- @parts.map do |part|
63
- case part
64
- when String then part
65
- when NonCodePart then f.(part.data)
66
- end
67
- end
68
- )
69
- end
70
-
71
- # @return [Enumerable<Object>] non-code parts of this {Code} introduced
72
- # with {::non_code}. See also {#map_non_code_parts}.
73
- def non_code_parts
74
- @parts.select { |part| part.is_a? NonCodePart }.map(&:data)
75
- end
76
-
77
- # @return [String]
78
- def to_s
79
- if (x = @parts.find { |part| part.is_a? NonCodePart }) then
80
- raise "non-code part: #{x.inspect}"
81
- end
82
- @parts.join
83
- end
84
-
85
- # @return [String]
86
- def inspect
87
- Inspectable.new(@parts, @metadata).inspect
88
- end
89
-
90
- # @api private
91
- # @note used by {Code}, {::non_code} only.
92
- NonCodePart = Struct.new :data
93
-
94
- protected
95
-
96
- # @!visibility private
97
- attr_reader :parts
98
-
99
- private
100
-
101
- # @!visibility private
102
- Inspectable = Struct.new :parts, :metadata
103
-
104
- end
105
-
106
- class Array
107
-
108
- # @param [Code, String] delimiter
109
- # @return [Code]
110
- def join_code(delimiter = "")
111
- self.reduce do |r, self_i|
112
- code << r << delimiter << self_i
113
- end or
114
- code
115
- end
116
-
117
- end
118
-
119
- # @overload code
120
- # @return [Code] an empty {Code}.
121
- # @overload code(str)
122
- # @param [String] str
123
- # @return [Code] +str+ converted to {Code}.
124
- def code(str = nil)
125
- if str
126
- then Code.new([str])
127
- else Code.new([])
128
- end
129
- end
130
-
131
- # @param [Object] data
132
- # @return [Code] a {Code} consisting of the single non-code part +data+.
133
- # See also {Code#non_code_parts}.
134
- def non_code(data)
135
- Code.new([Code::NonCodePart.new(data)])
136
- end
137
-
138
- alias __non_code__ non_code
@@ -1,468 +0,0 @@
1
- require 'strscan'
2
- require 'strscan/substr'
3
-
4
- # To disable YARD warnings:
5
- # @!parse
6
- # class Exception
7
- # def message
8
- # end
9
- # end
10
- # class Array
11
- # end
12
- # class String
13
- # end
14
-
15
- class Parse
16
-
17
- #
18
- # parses +text+.
19
- #
20
- # If $DEBUG == true then it prints {#rule} calls to stdout.
21
- #
22
- # @param [String] text
23
- # @param [String] file file the +text+ is taken from.
24
- # @raise [Parse::Error, IOError]
25
- # @return [Object] what {#start} returns (non-nil).
26
- #
27
- def call(text, file = "-")
28
- @text = StringScanner.new(text)
29
- @file = file
30
- @most_probable_error = nil
31
- @allow_errors = true
32
- @rule_start_pos = nil
33
- r = start()
34
- if r.nil? or not @text.eos? then
35
- if @most_probable_error
36
- then raise @most_probable_error
37
- else raise Error.new(Position.new(@text.pos, @text, @file), "syntax error")
38
- end
39
- end
40
- return r
41
- end
42
-
43
- class Position
44
-
45
- include Comparable
46
-
47
- # @api private
48
- # @note used by {Parse#pos} only
49
- # @param [Integer] text_pos
50
- # @param [StringScanner] text
51
- # @param [String] file
52
- def initialize(text_pos, text, file)
53
- @text = text
54
- @text_pos = text_pos
55
- @file = file
56
- end
57
-
58
- # @return [String]
59
- attr_reader :file
60
-
61
- # @return [Integer]
62
- def line
63
- line_and_column[0]
64
- end
65
-
66
- # @return [Integer]
67
- def column
68
- line_and_column[1]
69
- end
70
-
71
- # @param [Object] other
72
- # @return [-1, 0, 1, nil]
73
- def <=> other
74
- return nil unless other.is_a? Position and self.text.equal? other.text
75
- self.text_pos <=> other.text_pos
76
- end
77
-
78
- # @param [Object] other
79
- # @return [Boolean]
80
- def == other
81
- (self <=> other) == 0
82
- end
83
-
84
- # @!visibility private
85
- attr_reader :text_pos
86
-
87
- # @!visibility private
88
- attr_reader :text
89
-
90
- private
91
-
92
- def line_and_column
93
- @line_and_column ||= begin
94
- s = @text.substr(0, @text_pos)
95
- lines = s.split("\n", -1).to_a
96
- [
97
- line = if lines.size == 0 then 0 else lines.size - 1 end,
98
- column = (lines.last || "").size
99
- ].tap do
100
- @text = nil
101
- end
102
- end
103
- end
104
-
105
- end
106
-
107
- class Error < Exception
108
-
109
- # @param [Position] pos
110
- # @param [String] message
111
- def initialize(pos, message)
112
- super(message)
113
- @pos = pos
114
- end
115
-
116
- # @return [Position]
117
- attr_reader :pos
118
-
119
- # @param [Error] other +self+.{#pos} must be equal to +other+.{#pos}.
120
- # @return [Error] an {Error} with {Exception#message} combined from
121
- # {Exception#message}s of +self+ and +other+ (using "or" word).
122
- def or other
123
- raise "#{self.pos} == #{other.pos} is false" unless self.pos == other.pos
124
- Error.new(pos, "#{self.message} or #{other.message}")
125
- end
126
-
127
- end
128
-
129
- class Expected < Error
130
-
131
- # @param [Position] pos
132
- # @param [String] what_1
133
- # @param [*String] what_2_n
134
- def initialize(pos, what_1, *what_2_n)
135
- @what = [what_1, *what_2_n]
136
- super(pos, "#{@what.join(", ")} expected")
137
- end
138
-
139
- # (see Error#or)
140
- def or other
141
- if other.is_a? Expected
142
- raise "#{self.pos} == #{other.pos} is false" unless self.pos == other.pos
143
- Expected.new(pos, *(self.what + other.what).uniq)
144
- else
145
- super(other)
146
- end
147
- end
148
-
149
- protected
150
-
151
- # @!visibility private
152
- # @return [Array<String>]
153
- attr_reader :what
154
-
155
- end
156
-
157
- protected
158
-
159
- # @!method start()
160
- # @abstract
161
- #
162
- # Implementation of {#call}. Or the starting rule.
163
- #
164
- # @return [Object, nil] a result of parsing or nil if the parsing failed.
165
- # @raise [Parse::Error] if the parsing failed.
166
- # @raise [IOError]
167
- #
168
-
169
- # @return [Position] current {Position} in +text+ passed to {#call}.
170
- def pos
171
- Position.new(@text.pos, @text, @file)
172
- end
173
-
174
- #
175
- # scans +arg+ in +text+ passed to {#call} starting from {#pos} and,
176
- # if scanned successfully, advances {#pos} and returns the scanned
177
- # sub-{String}. Otherwise it calls {#expected} and returns nil.
178
- #
179
- # @param [String, Regexp] arg
180
- # @return [String, nil]
181
- #
182
- def scan(arg)
183
- case arg
184
- when Regexp then @text.scan(arg) or expected(pos, %(regexp "#{arg.source}"))
185
- when String then @text.scan(Regexp.new(Regexp.escape(arg))) or expected(pos, %("#{arg}"))
186
- end
187
- end
188
-
189
- # defines method +name+ with body +body+. Inside +body+ {#rule_start_pos}
190
- # is the value of {#pos} right before the defined method's call.
191
- #
192
- # @param [Symbol] name
193
- # @return [void]
194
- #
195
- def self.rule(name, &body)
196
- define_method(name) do
197
- old_rule_start_pos = @rule_start_pos
198
- @rule_start_pos = pos
199
- begin
200
- if $DEBUG then STDERR.puts("#{pos.file}:#{pos.line+1}:#{pos.column+1}: entering rule :#{name}"); end
201
- r = instance_eval(&body)
202
- if $DEBUG then STDERR.puts("#{pos.file}:#{pos.line+1}:#{pos.column+1}: exiting rule :#{name} #{if r.nil? then "(with nil)" end}"); end
203
- r
204
- ensure
205
- @rule_start_pos = old_rule_start_pos
206
- end
207
- end
208
- end
209
-
210
- # See {Parse::rule}.
211
- #
212
- # @return [Position]
213
- #
214
- attr_reader :rule_start_pos
215
-
216
- # @param [ASTNode] node
217
- # @return [ASTNode] +node+ which is
218
- # {ASTNode#initialize_pos}({#rule_start_pos})-ed.
219
- def _1(node)
220
- node.initialize_pos(rule_start_pos)
221
- end
222
-
223
- # is {#pos} at the end of the text?
224
- def end?
225
- @text.eos?
226
- end
227
-
228
- alias eos? end?
229
-
230
- # is {#pos} at the beginning of the text?
231
- def begin?
232
- @text.pos == 0
233
- end
234
-
235
- # alias for {#_1} and {#_2}
236
- def _(arg = nil, &block)
237
- if arg
238
- then _1(arg)
239
- else _2(&block)
240
- end
241
- end
242
-
243
- # --------------------------
244
- # @!group Parser Combinators
245
- # --------------------------
246
-
247
- # calls +f+ and returns true.
248
- #
249
- # @return [true]
250
- def act(&f)
251
- f.()
252
- true
253
- end
254
-
255
- #
256
- # calls +f+. If +f+ results in nil then it restores {#pos} to the
257
- # value before the call.
258
- #
259
- # @return what +f+ returns.
260
- #
261
- def _2(&f)
262
- old_text_pos = @text.pos
263
- f.() or begin
264
- @text.pos = old_text_pos
265
- nil
266
- end
267
- end
268
-
269
- # calls +f+ using {#_2} many times until it returns nil.
270
- #
271
- # @return [Array] an {Array} of non-nil results of +f+.
272
- #
273
- def many(&f)
274
- r = []
275
- while true
276
- f0 = _(&f)
277
- if f0
278
- then r.push(f0)
279
- else break
280
- end
281
- end
282
- r
283
- end
284
-
285
- # calls +f+ using {#_2}.
286
- #
287
- # @return [Array] an empty {Array} if +f+ results in nil and an {Array}
288
- # containing the single result of +f+ otherwise.
289
- #
290
- def opt(&f)
291
- [_(&f)].compact
292
- end
293
-
294
- # The same as <code>f.() and many(&f)</code>.
295
- #
296
- # @return [Array, nil] an {Array} of results of +f+ or nil if the first call
297
- # to +f+ returned nil.
298
- #
299
- def one_or_more(&f)
300
- f1 = f.() and f2_n = many(&f) and [f1, *f2_n]
301
- end
302
-
303
- alias many1 one_or_more
304
-
305
- # @overload not_follows(*method_ids)
306
- #
307
- # calls methods specified by +method_ids+. If any of them returns non-nil
308
- # then this method returns nil, otherwise it returns true. The methods
309
- # are called inside {#no_errors}. {#pos} is restored after each method's
310
- # call.
311
- #
312
- # @param [Array<Symbol>] method_ids
313
- # @return [true, nil]
314
- #
315
- # @overload not_follows(&f)
316
- #
317
- # calls +f+. If +f+ returns non-nil then this method returns nil,
318
- # otherwise it returns true. +f+ is called inside {#no_errors}.
319
- # {#pos} is restored after +f+'s call.
320
- #
321
- # @return [true, nil]
322
- #
323
- def not_follows(*method_ids, &f)
324
- if f then
325
- if no_errors { _{ f.() } }
326
- then nil
327
- else true
328
- end
329
- else # if not method_ids.empty? then
330
- if no_errors { method_ids.any? { |method_id| _{ __send__(method_id) } } }
331
- then nil
332
- else true
333
- end
334
- end
335
- end
336
-
337
- # ----------
338
- # @!endgroup
339
- # ----------
340
-
341
- # --------------
342
- # @!group Errors
343
- # --------------
344
-
345
- #
346
- # sets {#most_probable_error} to +error+ if it is more probable than
347
- # {#most_probable_error} or if {#most_probable_error} is nil.
348
- #
349
- # @param [Error] error
350
- # @return [nil]
351
- #
352
- def error(error)
353
- if @allow_errors then
354
- if @most_probable_error.nil? or @most_probable_error.pos < error.pos then
355
- @most_probable_error = error
356
- elsif @most_probable_error and @most_probable_error.pos == error.pos then
357
- @most_probable_error = @most_probable_error.or error
358
- else
359
- # do nothing
360
- end
361
- end
362
- return nil
363
- end
364
-
365
- # macro
366
- def expected(pos, what_1, *what_2_n)
367
- error(Expected.new(pos, what_1, *what_2_n))
368
- end
369
-
370
- # macro
371
- def expect(what_1, *what_2_n, &body)
372
- p = pos and body.() or expected(p, what_1, *what_2_n)
373
- end
374
-
375
- # calls +block+. Inside the +block+ {#error} has no effect.
376
- #
377
- # @return what +block+ returns.
378
- #
379
- def no_errors(&block)
380
- old_allow_errors = @allow_errors
381
- begin
382
- @allow_errors = false
383
- block.()
384
- ensure
385
- @allow_errors = old_allow_errors
386
- end
387
- end
388
-
389
- # @return [Error, nil]
390
- attr_reader :most_probable_error
391
-
392
- # ----------
393
- # @!endgroup
394
- # ----------
395
-
396
- end
397
-
398
- module ASTNode
399
-
400
- # macro
401
- def self.new(*properties, &body)
402
- (if properties.empty? then Class.new else Struct.new(*properties); end).tap do |c|
403
- c.class_eval do
404
-
405
- include ASTNode
406
-
407
- # @return [Boolean]
408
- def === other
409
- self.class == other.class and
410
- self.members.all? { |member| self.__send__(member) === other.__send__(member) }
411
- end
412
-
413
- if properties.empty? then
414
- # @return [Array<Symbol>]
415
- def members
416
- []
417
- end
418
- end
419
-
420
- end
421
- c.class_eval(&body) if body
422
- end
423
- end
424
-
425
- # @param [Parse::Position] pos
426
- # @return [self]
427
- def initialize_pos(pos)
428
- @pos = pos
429
- self
430
- end
431
-
432
- # @note {#initialize_pos} must be called before this method can be used.
433
- # @return [Parse::Position]
434
- def pos
435
- raise "initialize_pos() must be called before this method can be used" unless @pos
436
- @pos
437
- end
438
-
439
- end
440
-
441
- # Alias for {ASTNode#new}.
442
- def node(*properties, &body)
443
- ASTNode.new(*properties, &body)
444
- end
445
-
446
- # class Calc < Parse
447
- #
448
- # Number = ASTNode.new :val
449
- #
450
- # rule :start do
451
- # x1 = number and x2 = many { comma and number } and [x1, *x2]
452
- # end
453
- #
454
- # rule :number do
455
- # s = scan(/\d+/) and _(Number[s])
456
- # end
457
- #
458
- # rule :comma do
459
- # scan(",")
460
- # end
461
- #
462
- # end
463
- #
464
- # begin
465
- # p Calc.new.("10, 20", __FILE__)
466
- # rescue Parse::Error => e
467
- # puts "error: #{e.pos.file}:#{e.pos.line}:#{e.pos.column}: #{e.message}"
468
- # end
@@ -1,16 +0,0 @@
1
-
2
- class StringScanner
3
-
4
- # @param [Integer] start some value of {StringScanner#pos}.
5
- # @param [Integer] end_ some value of {StringScanner#pos}.
6
- # @return [String]
7
- def substr(start, end_)
8
- old_pos = self.pos
9
- self.pos = start
10
- result = peek(end_ - start)
11
- self.pos = old_pos
12
- return result
13
- end
14
-
15
- end
16
-