flydata 0.2.7 → 0.2.8

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: bfd589bd9943f41f8e817ec796aa74aef758d1f9
4
- data.tar.gz: dc62b1dde189197fb3552abde072b40697e92dd5
3
+ metadata.gz: c5fda2fb95c38692e1a0995b3ee7430ea706ec09
4
+ data.tar.gz: 5028033ad26d7399e7bcb091257540f1fb4ab46a
5
5
  SHA512:
6
- metadata.gz: 34006fd5e1f6052f901b92df572ae71c64e3deea4449d3c92aded6cf7013ecf5cd142e2d875c800c5778a5962af5d8add5627e315c3a46806df5980e8bbabceb
7
- data.tar.gz: 9a7b312e2c03d2048878f211a6c0233d5d9d31bf7cce0cf655a75bc14287e226094779a45d0dd67df81d1b9f6d19aca1f74a4c04870da4fe6a969bcb4fa34ac5
6
+ metadata.gz: dbcb9055ead8575095ef96d378d2817743f0c03cb629d6d7ef5d46bc99f04fd22e420f2c8011c28a97a3c5041ec683ed57045d59bd86c31fdb6ec680dbb81769
7
+ data.tar.gz: 1e77c0720dd22cad760cd00f11eef55514bb768937acb5b6970027f352d5cf97d9f2177b6d904aeb74c8716ab6f9f374757f3ce09780e3c166f79ad3b6a7360d
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.2.8
data/flydata.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: flydata 0.2.7 ruby lib
5
+ # stub: flydata 0.2.8 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "flydata"
9
- s.version = "0.2.7"
9
+ s.version = "0.2.8"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Koichi Fujikawa", "Masashi Miyazaki", "Matthew Luu", "Mak Inada", "Sriram NS"]
14
- s.date = "2014-10-07"
14
+ s.date = "2014-10-15"
15
15
  s.description = "FlyData Agent"
16
16
  s.email = "sysadmin@flydata.com"
17
17
  s.executables = ["fdmysqldump", "flydata", "serverinfo"]
@@ -35,8 +35,14 @@ module Flydata
35
35
  end
36
36
  def ask_yes_no(message, default_yes=true)
37
37
  suffix = default_yes ? "(Y/n)" : "(y/n)"
38
+ prompt = "#{message} #{suffix}: "
39
+ if opts && opts.yes? # Yes option
40
+ puts "#{prompt}Yes"
41
+ return true
42
+ end
43
+
38
44
  loop do
39
- ans = ask("#{message} #{suffix}: ")
45
+ ans = ask(prompt)
40
46
  return true if default_yes and ans == ''
41
47
  if ans.size > 0
42
48
  case ans[0].downcase
@@ -21,6 +21,7 @@ module Flydata
21
21
  def self.slop
22
22
  Slop.new do
23
23
  on 'c', 'skip-cleanup', 'Skip server cleanup'
24
+ on 'y', 'yes', 'Skip command prompt assuming yes to all questions. Use this for batch operation.'
24
25
  end
25
26
  end
26
27
 
@@ -42,6 +43,12 @@ module Flydata
42
43
  sync_mysql_to_redshift(de)
43
44
  end
44
45
 
46
+ def self.slop_flush
47
+ Slop.new do
48
+ on 'y', 'yes', 'Skip command prompt assuming yes to all questions. Use this for batch operation.'
49
+ end
50
+ end
51
+
45
52
  def flush
46
53
  flush_buffer_and_stop
47
54
  puts "Buffers have been flushed and the sender process has been stopped."
@@ -50,6 +57,7 @@ module Flydata
50
57
  def self.slop_reset
51
58
  Slop.new do
52
59
  on 'c', 'client', 'Resets client only.'
60
+ on 'y', 'yes', 'Skip command prompt assuming yes to all questions. Use this for batch operation.'
53
61
  end
54
62
  end
55
63
 
@@ -134,6 +142,7 @@ module Flydata
134
142
  def self.slop_generate_table_ddl
135
143
  Slop.new do
136
144
  on 'c', 'ctl-only', 'Only generate FlyData Control definitions'
145
+ on 'y', 'yes', 'Skip command prompt assuming yes to all questions. Use this for batch operation.'
137
146
  end
138
147
  end
139
148
 
@@ -14,14 +14,16 @@ module Mysql
14
14
  end
15
15
 
16
16
  def process(record, normalized_query)
17
- emit_record(:alter_table, record, increment_table_rev: true) do
17
+ emit_record(:alter_table, record) do |opt|
18
18
  ret = nil
19
19
  begin
20
20
  result = ParserProvider.parser(:mysql, :mysql_alter_table).new.parse(record['query'])
21
21
  if result.nil?
22
- $log.warn("Received unsupported alter table query. query:'#{record['query']}'")
22
+ $log.error("Received unsupported alter table query. query:'#{record['query']}'")
23
23
  else
24
24
  ret = result.tree
25
+ breaking_query = ret[:actions].any?{|action| !action.has_key?(:support_level) || action[:support_level] != :nonbreaking}
26
+ opt[:increment_table_rev] = true if breaking_query
25
27
  end
26
28
  rescue => e
27
29
  msg = <<EOS
@@ -54,13 +54,14 @@ module Mysql
54
54
  @context.omit_events[table].nil? || !@context.omit_events[table].include?(type)
55
55
  end
56
56
 
57
- def emit_record(type, record, opt = {})
57
+ def emit_record(type, record)
58
58
  return unless acceptable_db?(record)
59
59
  return unless record["table_name"].nil? or acceptable_table?(record, record["table_name"])
60
60
 
61
61
  check_empty_binlog
62
62
 
63
- records = yield
63
+ opt = {}
64
+ records = yield(opt) # The block may set options as necessary
64
65
  return if records.nil? # skip
65
66
  records = [records] unless records.kind_of?(Array)
66
67
 
@@ -41,7 +41,7 @@ module Mysql
41
41
  end
42
42
 
43
43
  def emit_rows(type, record)
44
- emit_record(type, record) do |table|
44
+ emit_record(type, record) do |opt|
45
45
  records = record["rows"].collect do |row|
46
46
  row = yield(row) if block_given? # Give the caller a chance to generate the correct row
47
47
  { ROW => convert_to_flydata_row_format(row) }
@@ -20,10 +20,10 @@ grammar MysqlAlterTable
20
20
  def tree
21
21
  value = {
22
22
  type: :alter_table,
23
- table_name: tbl_name.table_part.text_value,
23
+ table_name: tbl_name.table_part.value,
24
24
  actions: alter_specs.actions
25
25
  }
26
- value[:schema_name] = tbl_name.schema_part.text_value if tbl_name.has_schema?
26
+ value[:schema_name] = tbl_name.schema_part.value if tbl_name.has_schema?
27
27
  value
28
28
  end
29
29
  }
@@ -41,27 +41,34 @@ grammar MysqlAlterTable
41
41
  alter_spec ( comma alter_spec )* {
42
42
  def actions
43
43
  ret = []
44
- concat_action!(ret, alter_spec.action)
44
+ ret.concat(actions_with_query(alter_spec))
45
45
  0.upto(elements[1].elements.size - 1) do |i|
46
- action = elements[1].elements[i].elements[1].action
47
- concat_action!(ret, action)
46
+ ret.concat(actions_with_query(elements[1].elements[i].elements[1]))
48
47
  end
49
48
  ret
50
49
  end
51
50
 
52
- def concat_action!(array, action)
51
+ def actions_with_query(alter_spec)
52
+ action = alter_spec.action
53
53
  if action.kind_of?(Array)
54
54
  actions = action
55
55
  else
56
56
  actions = [action]
57
57
  end
58
- array.concat(actions)
58
+ actions.each {|a| a[:query] = alter_spec.text_value }
59
+ actions
59
60
  end
60
61
  }
61
62
  end
62
63
 
63
64
  rule alter_spec
64
- add_key (sp col_key)? sp col_name_def ( sp pos_def )? {
65
+ add_key sp key_def {
66
+ def action
67
+ action_hash = key_def.action
68
+ action_hash
69
+ end
70
+ }
71
+ / add_key (sp col_key)? sp col_name_def ( sp pos_def )? {
65
72
  def action
66
73
  ret = { action: :add_column }
67
74
  ret.merge!(col_name_def.column_def)
@@ -71,7 +78,7 @@ grammar MysqlAlterTable
71
78
  ret
72
79
  end
73
80
  }
74
- / add_key (sp col_key)? sp '(' nsp col_name_def ( comma col_name_def )* nsp ')' {
81
+ / add_key (sp col_key)? nsp '(' nsp col_name_def ( comma col_name_def )* nsp ')' {
75
82
  def action
76
83
  ret = [col_name_def.column_def]
77
84
  ret += 0.upto(elements[6].elements.count - 1).collect do |i|
@@ -80,19 +87,423 @@ grammar MysqlAlterTable
80
87
  ret.collect{|v| {action: :add_column}.merge(v) }
81
88
  end
82
89
  }
90
+ / drop_key sp primary_sym sp key_sym {
91
+ def action
92
+ { action: :drop_primary_key }
93
+ end
94
+ }
95
+ / drop_key sp foreign_sym sp key_sym sp field_ident {
96
+ def action
97
+ { action: :drop_foreign_key,
98
+ support_level: :nonbreaking
99
+ }
100
+ end
101
+ }
102
+ / drop_key sp key_or_index sp field_ident {
103
+ def action
104
+ { action: "drop_#{key_or_index.text_value.downcase}".to_sym,
105
+ support_level: :nonbreaking
106
+ }
107
+ end
108
+ }
83
109
  / drop_key (sp col_key)? sp col_name {
84
110
  def action
85
111
  { action: :drop_column,
86
- column: col_name.text_value, }
112
+ column: col_name.value, }
113
+ end
114
+ }
115
+ / enable_sym sp keys_sym {
116
+ def action
117
+ { action: :enable_keys,
118
+ support_level: :nonbreaking,
119
+ }
120
+ end
121
+ }
122
+ / [^,]+ {
123
+ def action
124
+ raise "unsupported ALTER TABLE query. Contact FlyData Support"
87
125
  end
88
126
  }
89
- / [^,]+
127
+ end
128
+
129
+ rule key_def
130
+ normal_key_type key_alg nsp '(' key_list ')' normal_key_options {
131
+ def action
132
+ { action: :add_index,
133
+ support_level: :nonbreaking,
134
+ }
135
+ end
136
+ }
137
+ / normal_key_type opt_ident key_alg nsp '(' key_list ')' normal_key_options {
138
+ def action
139
+ { action: :add_index,
140
+ support_level: :nonbreaking,
141
+ }
142
+ end
143
+ }
144
+ / fulltext opt_key_or_index opt_ident init_key_options nsp '(' key_list ')' fulltext_key_options {
145
+ def action
146
+ { action: :add_index,
147
+ support_level: :nonbreaking,
148
+ }
149
+ end
150
+ }
151
+ / spatial opt_key_or_index opt_ident init_key_options nsp '(' key_list ')' spatial_key_options {
152
+ def action
153
+ { action: :add_index,
154
+ support_level: :nonbreaking,
155
+ }
156
+ end
157
+ }
158
+ / constraint_sym sp constraint_key_type key_alg nsp '(' key_list ')' normal_key_options {
159
+ def action
160
+ case constraint_key_type.value
161
+ when :unique
162
+ { action: :add_unique_constraint,
163
+ support_level: :nonbreaking
164
+ }
165
+ when :primary_key
166
+ { action: :add_primary_key_constraint,
167
+ keys: key_list.value
168
+ }
169
+ else
170
+ raise "Unsupported constraint key type `#{constraint_key_type.value}"
171
+ end
172
+ end
173
+ }
174
+ / constraint_sym sp constraint_key_type opt_ident key_alg nsp '(' key_list ')' normal_key_options {
175
+ def action
176
+ case constraint_key_type.value
177
+ when :unique
178
+ { action: :add_unique_constraint,
179
+ support_level: :nonbreaking
180
+ }
181
+ when :primary_key
182
+ { action: :add_primary_key_constraint,
183
+ keys: key_list.value
184
+ }
185
+ else
186
+ raise "Unsupported constraint key type `#{constraint_key_type.value}"
187
+ end
188
+ end
189
+ }
190
+ / opt_constraint constraint_key_type key_alg nsp '(' key_list ')' normal_key_options {
191
+ def action
192
+ case constraint_key_type.value
193
+ when :unique
194
+ { action: :add_unique_constraint,
195
+ support_level: :nonbreaking
196
+ }
197
+ when :primary_key
198
+ { action: :add_primary_key_constraint,
199
+ keys: key_list.value
200
+ }
201
+ else
202
+ raise "Unsupported constraint key type `#{constraint_key_type.value}"
203
+ end
204
+ end
205
+ }
206
+ / opt_constraint constraint_key_type opt_ident key_alg nsp '(' key_list ')' normal_key_options {
207
+ def action
208
+ case constraint_key_type.value
209
+ when :unique
210
+ { action: :add_unique_constraint,
211
+ support_level: :nonbreaking
212
+ }
213
+ when :primary_key
214
+ { action: :add_primary_key_constraint,
215
+ keys: key_list.value
216
+ }
217
+ else
218
+ raise "Unsupported constraint key type `#{constraint_key_type.value}"
219
+ end
220
+ end
221
+ }
222
+ / opt_constraint 'foreign'i key_sym opt_ident nsp '(' key_list ')' sp references
223
+ / constraint_sym sp check_constraint {
224
+ def action
225
+ { action: :add_check_constraint,
226
+ support_level: :nonbreaking,
227
+ }
228
+ end
229
+ }
230
+ / opt_constraint check_constraint {
231
+ def action
232
+ { action: :add_check_constraint,
233
+ support_level: :nonbreaking,
234
+ }
235
+ end
236
+ }
237
+ end
238
+
239
+ rule check_constraint
240
+ 'check'i nsp '(' nsp expr nsp ')'
241
+ end
242
+
243
+ rule expr
244
+ ( !')' . )+
245
+ end
246
+
247
+ rule references
248
+ 'references'i sp table_ident opt_ref_list opt_match_clause opt_on_update_delete
249
+ end
250
+
251
+ rule table_ident
252
+ ident '.' ident
253
+ / '.' ident
254
+ / ident
255
+ end
256
+
257
+ rule opt_ref_list
258
+ ( nsp '(' nsp ref_list nsp ')' )?
259
+ end
260
+
261
+ rule ref_list
262
+ ident comma ref_list
263
+ / ident
264
+ end
265
+
266
+ rule opt_match_clause
267
+ ( sp ( 'match'i sp 'full'i / 'match'i sp 'partial'i / 'match'i sp 'simple'i ) )?
268
+ end
269
+
270
+ rule opt_on_update_delete
271
+ ( sp (
272
+ 'on'i sp 'update'i delete_option sp 'on'i sp 'delete'i sp delete_option
273
+ / 'on'i sp 'delete'i delete_option sp 'on'i sp 'update'i sp delete_option
274
+ / 'on'i sp 'update'i sp delete_option
275
+ / 'on'i sp 'delete'i sp delete_option
276
+ )
277
+ )?
278
+ end
279
+
280
+ rule delete_option
281
+ 'restrict'i
282
+ / 'cascade'i
283
+ / 'set'i sp 'null'i
284
+ / 'no'i sp 'action'i
285
+ / 'set'i sp 'default'i
286
+ end
287
+
288
+ rule opt_constraint
289
+ ( constraint sp )?
290
+ end
291
+
292
+ rule constraint
293
+ constraint_sym opt_ident
294
+ end
295
+
296
+ rule constraint_sym
297
+ 'constraint'i
298
+ end
299
+
300
+ rule constraint_key_type
301
+ primary_sym sp key_sym {
302
+ # #value returns a normalized value of the element while #text_value
303
+ # returns its text as is
304
+ def value
305
+ :primary_key
306
+ end
307
+ }
308
+ / unique_sym opt_key_or_index {
309
+ def value
310
+ :unique
311
+ end
312
+ }
313
+ end
314
+
315
+ rule primary_sym
316
+ 'primary'i
317
+ end
318
+
319
+ rule key_sym
320
+ 'key'i
321
+ end
322
+
323
+ rule keys_sym
324
+ 'keys'i
325
+ end
326
+
327
+ rule unique_sym
328
+ 'unique'i
329
+ end
330
+
331
+ rule index_sym
332
+ 'index'i
333
+ end
334
+
335
+ rule enable_sym
336
+ 'enable'i
337
+ end
338
+
339
+ rule foreign_sym
340
+ 'foreign'i
341
+ end
342
+
343
+ rule fulltext
344
+ 'fulltext'i
345
+ end
346
+
347
+ rule fulltext_key_options
348
+ ( sp fulltext_key_opts )?
349
+ end
350
+
351
+ rule fulltext_key_opts
352
+ fulltext_key_opt sp fulltext_key_opts
353
+ / fulltext_key_opt
354
+ end
355
+
356
+ rule fulltext_key_opt
357
+ all_key_opt
358
+ / 'with parser'i sp ident_sys
359
+ end
360
+
361
+ rule spatial
362
+ 'spatial'i
363
+ end
364
+
365
+ rule spatial_key_options
366
+ ( sp spatial_key_opts )?
367
+ end
368
+
369
+ rule spatial_key_opts
370
+ spatial_key_opt sp spatial_key_opts
371
+ / spatial_key_opt
372
+ end
373
+
374
+ rule spatial_key_opt
375
+ all_key_opt
376
+ end
377
+
378
+ rule opt_key_or_index
379
+ ( sp key_or_index )?
380
+ end
381
+
382
+ rule normal_key_type
383
+ key_or_index
384
+ end
385
+
386
+ rule key_or_index
387
+ key_sym / index_sym
388
+ end
389
+
390
+ rule opt_ident
391
+ ( sp field_ident )?
392
+ end
393
+
394
+ rule field_ident
395
+ ident '.' ident '.' ident
396
+ / ident '.' ident
397
+ / '.' ident
398
+ / ident
399
+ end
400
+
401
+ rule key_alg
402
+ sp init_key_options key_using_alg
403
+ / init_key_options
404
+ end
405
+
406
+ rule init_key_options
407
+ '' # In original, this is doing some initialization
408
+ end
409
+
410
+ rule key_using_alg
411
+ 'using'i sp btree_or_rtree
412
+ / type_sym sp btree_or_rtree
413
+ end
414
+
415
+ rule btree_or_rtree
416
+ 'btree'i / 'rtree'i / 'hash'i
417
+ end
418
+
419
+ rule type_sym
420
+ 'type'i
421
+ end
422
+
423
+ rule key_list
424
+ nsp key_part order_dir nsp ',' nsp key_list nsp {
425
+ # #value returns a normalized value of the element while #text_value
426
+ # returns its text as is
427
+ def value
428
+ order_dir_value = order_dir.value
429
+ if order_dir_value && !order_dir_value.empty?
430
+ order_dir_value = " " + order_dir_value
431
+ end
432
+ [ "#{key_part.value}#{order_dir_value}" ] + key_list.value
433
+ end
434
+ }
435
+ / nsp key_part order_dir nsp {
436
+ def value
437
+ order_dir_value = order_dir.value
438
+ if order_dir_value && !order_dir_value.empty?
439
+ order_dir_value = " " + order_dir_value
440
+ end
441
+ [ "#{key_part.value}#{order_dir_value}" ]
442
+ end
443
+ }
444
+ end
445
+
446
+ rule key_part
447
+ ident nsp '(' nsp num nsp ')' {
448
+ # #value returns a normalized value of the element while #text_value
449
+ # returns its text as is
450
+ def value
451
+ "#{ident.value}(#{num.text_value})"
452
+ end
453
+ }
454
+ / ident
455
+ end
456
+
457
+ rule order_dir
458
+ # Treetop creates an empty SyntaxNode if the rule results in "match none"
459
+ # The SyntaxNode instance does not have a custom method as deinfed here,
460
+ # so it causes an issue to other nodes expecting the method.
461
+ # 1..1 is a magic trick to force Treetop creating a SyntaxNode with
462
+ # the custom method.
463
+ (( sp ('asc'i / 'desc'i) )?) 1..1 {
464
+ def value
465
+ text_value.strip.downcase
466
+ end
467
+ }
468
+ end
469
+
470
+ rule normal_key_options
471
+ ( sp normal_key_opts )?
472
+ end
473
+
474
+ rule normal_key_opts
475
+ normal_key_opt sp normal_key_opts
476
+ / normal_key_opt
477
+ end
478
+
479
+ rule normal_key_opt
480
+ all_key_opt
481
+ / key_using_alg
482
+ end
483
+
484
+ rule all_key_opt
485
+ key_block_size nsp equal nsp ulong_num
486
+ / key_block_size sp ulong_num
487
+ / comment_opt
488
+ end
489
+
490
+ rule opt_equal
491
+ ( nsp equal )?
492
+ end
493
+
494
+ rule equal
495
+ '='
496
+ / ':='
497
+ end
498
+
499
+ rule key_block_size
500
+ 'key_block_size'i
90
501
  end
91
502
 
92
503
  rule col_name_def
93
504
  col_name sp col_def {
94
505
  def column_def
95
- {column: col_name.text_value}.merge(col_def.column_def)
506
+ {column: col_name.value}.merge(col_def.column_def)
96
507
  end
97
508
  }
98
509
  end
@@ -105,7 +516,7 @@ grammar MysqlAlterTable
105
516
  }
106
517
  / 'after'i sp col_name {
107
518
  def pos_def_option
108
- { after: col_name.text_value, }
519
+ { after: col_name.value, }
109
520
  end
110
521
  }
111
522
  end
@@ -158,7 +569,7 @@ grammar MysqlAlterTable
158
569
  end
159
570
 
160
571
  rule data_type_name
161
- ident ''
572
+ ident_sym ''
162
573
  end
163
574
 
164
575
  rule meta_text
@@ -248,6 +659,14 @@ grammar MysqlAlterTable
248
659
  [0-9]* '.' [0-9]+ { def text_value; v = super; v.start_with?('.') ? "0#{v}" : v; end }
249
660
  / [0-9]+
250
661
  end
662
+ rule num
663
+ [0-9]+
664
+ end
665
+
666
+ rule ulong_num
667
+ [0-9]+ # TODO May not be the correct definition
668
+ end
669
+
251
670
  rule auto_increment_opt
252
671
  'auto_increment'i
253
672
  end
@@ -325,7 +744,7 @@ grammar MysqlAlterTable
325
744
 
326
745
  rule value
327
746
  quoted_value { def raw_value; text_raw_value; end }
328
- / ident { def raw_value; text_value; end }
747
+ / ident_sym { def raw_value; text_value; end }
329
748
  end
330
749
 
331
750
  rule quoted_value
@@ -333,21 +752,41 @@ grammar MysqlAlterTable
333
752
  end
334
753
 
335
754
  rule text
336
- ("\\\\" / "\\'" / !"'" .)*
755
+ ("\\\\" / "\\'" / !"'" . )*
756
+ end
757
+
758
+ rule ident
759
+ ident_sys / keyword
760
+ end
761
+
762
+ rule keyword
763
+ ([a-zA-Z_]+) 1..1 { # TODO list all keywords
764
+ def value
765
+ text_value
766
+ end
767
+ }
337
768
  end
338
769
 
339
770
  rule ident_sys
340
- ident / ident_quoted
771
+ ident_sym / ident_quoted
341
772
  end
342
773
 
343
- rule ident
344
- [0-9a-zA-Z_]+
774
+ rule ident_sym
775
+ # 1..1 prevents Treetop from embedding the SyntaxNode to an upper node
776
+ # without the custom method.
777
+ ([0-9a-zA-Z_]+) 1..1 {
778
+ def value
779
+ text_value
780
+ end
781
+ }
345
782
  end
346
783
 
347
784
  rule ident_quoted
348
- '`' ident '`' {
349
- def text_value
350
- ident.text_value
785
+ '`' ident_sym '`' {
786
+ # #value returns a normalized value of the element while #text_value
787
+ # returns its text as is
788
+ def value
789
+ ident_sym.value
351
790
  end
352
791
  }
353
792
  end