Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

* parse.y: added symbols and qsymbols productions for %i and %I

  support. %i{ .. } returns a list of symbols without interpolation,
  %I{ .. } returns a list of symbols with interpolation.  Thanks to
  Josh Susser for inspiration of this feature. [Feature #4985]

* ext/ripper/eventids2.c: added ripper events for %i and %I.

* test/ripper/test_parser_events.rb: ripper tests

* test/ripper/test_scanner_events.rb: ditto

* test/ruby/test_array.rb: test for %i and %I behavior

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36524 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
commit 91bd6e711db3418baa287e936d4b0fac99927711 1 parent 1a5773a
Aaron Patterson authored July 24, 2012
15  ChangeLog
... ...
@@ -1,3 +1,18 @@
  1
+Wed Jul 25 03:05:06 2012  Aaron Patterson <aaron@tenderlovemaking.com>
  2
+
  3
+	* parse.y: added symbols and qsymbols productions for %i and %I
  4
+	  support. %i{ .. } returns a list of symbols without interpolation,
  5
+	  %I{ .. } returns a list of symbols with interpolation.  Thanks to
  6
+	  Josh Susser for inspiration of this feature. [Feature #4985]
  7
+
  8
+	* ext/ripper/eventids2.c: added ripper events for %i and %I.
  9
+
  10
+	* test/ripper/test_parser_events.rb: ripper tests
  11
+
  12
+	* test/ripper/test_scanner_events.rb: ditto
  13
+
  14
+	* test/ruby/test_array.rb: test for %i and %I behavior
  15
+
1 16
 Tue Jul 24 23:34:43 2012  Hiroshi Shirosaki  <h.shirosaki@gmail.com>
2 17
 
3 18
 	* include/ruby/win32.h (rb_w32_pow): add new function.
3  NEWS
@@ -169,6 +169,9 @@ with all sufficient information, see the ChangeLog file.
169 169
     long.
170 170
 
171 171
 === Language changes
  172
+
  173
+  * Added %i and %I for symbol list creation (similar to %w and %W).
  174
+
172 175
 === Compatibility issues (excluding feature bug fixes)
173 176
 
174 177
   * Signal.trap
6  ext/ripper/eventids2.c
@@ -38,6 +38,8 @@ static ID ripper_id_tstring_content;
38 38
 static ID ripper_id_tstring_end;
39 39
 static ID ripper_id_words_beg;
40 40
 static ID ripper_id_qwords_beg;
  41
+static ID ripper_id_qsymbols_beg;
  42
+static ID ripper_id_symbols_beg;
41 43
 static ID ripper_id_words_sep;
42 44
 static ID ripper_id_regexp_beg;
43 45
 static ID ripper_id_regexp_end;
@@ -91,6 +93,8 @@ ripper_init_eventids2(void)
91 93
     ripper_id_tstring_end = rb_intern_const("on_tstring_end");
92 94
     ripper_id_words_beg = rb_intern_const("on_words_beg");
93 95
     ripper_id_qwords_beg = rb_intern_const("on_qwords_beg");
  96
+    ripper_id_qsymbols_beg = rb_intern_const("on_qsymbols_beg");
  97
+    ripper_id_symbols_beg = rb_intern_const("on_symbols_beg");
94 98
     ripper_id_words_sep = rb_intern_const("on_words_sep");
95 99
     ripper_id_regexp_beg = rb_intern_const("on_regexp_beg");
96 100
     ripper_id_regexp_end = rb_intern_const("on_regexp_end");
@@ -228,6 +232,8 @@ static const struct token_assoc {
228 232
     {tOROP,		&ripper_id_op},
229 233
     {tPOW,		&ripper_id_op},
230 234
     {tQWORDS_BEG,	&ripper_id_qwords_beg},
  235
+    {tQSYMBOLS_BEG,	&ripper_id_qsymbols_beg},
  236
+    {tSYMBOLS_BEG,	&ripper_id_symbols_beg},
231 237
     {tREGEXP_BEG,	&ripper_id_regexp_beg},
232 238
     {tREGEXP_END,	&ripper_id_regexp_end},
233 239
     {tRPAREN,		&ripper_id_rparen},
98  parse.y
@@ -715,7 +715,7 @@ static void token_info_pop(struct parser_params*, const char *token);
715 715
 
716 716
 %type <node> singleton strings string string1 xstring regexp
717 717
 %type <node> string_contents xstring_contents regexp_contents string_content
718  
-%type <node> words qwords word_list qword_list word
  718
+%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
719 719
 %type <node> literal numeric dsym cpath
720 720
 %type <node> top_compstmt top_stmts top_stmt
721 721
 %type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
@@ -769,7 +769,7 @@ static void token_info_pop(struct parser_params*, const char *token);
769 769
 %token tDSTAR		/* ** */
770 770
 %token tAMPER		/* & */
771 771
 %token tLAMBDA		/* -> */
772  
-%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG
  772
+%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG
773 773
 %token tSTRING_DBEG tSTRING_DEND tSTRING_DVAR tSTRING_END tLAMBEG
774 774
 
775 775
 /*
@@ -2672,6 +2672,8 @@ primary		: literal
2672 2672
 		| regexp
2673 2673
 		| words
2674 2674
 		| qwords
  2675
+		| symbols
  2676
+		| qsymbols
2675 2677
 		| var_ref
2676 2678
 		| backref
2677 2679
 		| tFID
@@ -4105,6 +4107,45 @@ word		: string_content
4105 4107
 		    }
4106 4108
 		;
4107 4109
 
  4110
+symbols	        : tSYMBOLS_BEG ' ' tSTRING_END
  4111
+		    {
  4112
+		    /*%%%*/
  4113
+			$$ = NEW_ZARRAY();
  4114
+		    /*%
  4115
+			$$ = dispatch0(symbols_new);
  4116
+			$$ = dispatch1(array, $$);
  4117
+		    %*/
  4118
+		    }
  4119
+		| tSYMBOLS_BEG symbol_list tSTRING_END
  4120
+		    {
  4121
+		    /*%%%*/
  4122
+			$$ = $2;
  4123
+		    /*%
  4124
+			$$ = dispatch1(array, $2);
  4125
+		    %*/
  4126
+		    }
  4127
+		;
  4128
+
  4129
+symbol_list	: /* none */
  4130
+		    {
  4131
+		    /*%%%*/
  4132
+			$$ = 0;
  4133
+		    /*%
  4134
+			$$ = dispatch0(symbols_new);
  4135
+		    %*/
  4136
+		    }
  4137
+		| symbol_list word ' '
  4138
+		    {
  4139
+		    /*%%%*/
  4140
+			$2 = evstr2dstr($2);
  4141
+			nd_set_type($2, NODE_DSYM);
  4142
+			$$ = list_append($1, $2);
  4143
+		    /*%
  4144
+			$$ = dispatch2(symbols_add, $1, $2);
  4145
+		    %*/
  4146
+		    }
  4147
+		;
  4148
+
4108 4149
 qwords		: tQWORDS_BEG ' ' tSTRING_END
4109 4150
 		    {
4110 4151
 		    /*%%%*/
@@ -4124,6 +4165,25 @@ qwords		: tQWORDS_BEG ' ' tSTRING_END
4124 4165
 		    }
4125 4166
 		;
4126 4167
 
  4168
+qsymbols	: tQSYMBOLS_BEG ' ' tSTRING_END
  4169
+		    {
  4170
+		    /*%%%*/
  4171
+			$$ = NEW_ZARRAY();
  4172
+		    /*%
  4173
+			$$ = dispatch0(qsymbols_new);
  4174
+			$$ = dispatch1(array, $$);
  4175
+		    %*/
  4176
+		    }
  4177
+		| tQSYMBOLS_BEG qsym_list tSTRING_END
  4178
+		    {
  4179
+		    /*%%%*/
  4180
+			$$ = $2;
  4181
+		    /*%
  4182
+			$$ = dispatch1(array, $2);
  4183
+		    %*/
  4184
+		    }
  4185
+		;
  4186
+
4127 4187
 qword_list	: /* none */
4128 4188
 		    {
4129 4189
 		    /*%%%*/
@@ -4142,6 +4202,28 @@ qword_list	: /* none */
4142 4202
 		    }
4143 4203
 		;
4144 4204
 
  4205
+qsym_list	: /* none */
  4206
+		    {
  4207
+		    /*%%%*/
  4208
+			$$ = 0;
  4209
+		    /*%
  4210
+			$$ = dispatch0(qsymbols_new);
  4211
+		    %*/
  4212
+		    }
  4213
+		| qsym_list tSTRING_CONTENT ' '
  4214
+		    {
  4215
+		    /*%%%*/
  4216
+			VALUE lit;
  4217
+			lit = $2->nd_lit;
  4218
+			$2->nd_lit = ID2SYM(rb_intern_str(lit));
  4219
+			nd_set_type($2, NODE_LIT);
  4220
+			$$ = list_append($1, $2);
  4221
+		    /*%
  4222
+			$$ = dispatch2(qsymbols_add, $1, $2);
  4223
+		    %*/
  4224
+		    }
  4225
+		;
  4226
+
4145 4227
 string_contents : /* none */
4146 4228
 		    {
4147 4229
 		    /*%%%*/
@@ -7796,6 +7878,18 @@ parser_yylex(struct parser_params *parser)
7796 7878
 		pushback(c);
7797 7879
 		return tQWORDS_BEG;
7798 7880
 
  7881
+	      case 'I':
  7882
+		lex_strterm = NEW_STRTERM(str_dword, term, paren);
  7883
+		do {c = nextc();} while (ISSPACE(c));
  7884
+		pushback(c);
  7885
+		return tSYMBOLS_BEG;
  7886
+
  7887
+	      case 'i':
  7888
+		lex_strterm = NEW_STRTERM(str_sword, term, paren);
  7889
+		do {c = nextc();} while (ISSPACE(c));
  7890
+		pushback(c);
  7891
+		return tQSYMBOLS_BEG;
  7892
+
7799 7893
 	      case 'x':
7800 7894
 		lex_strterm = NEW_STRTERM(str_xquote, term, paren);
7801 7895
 		return tXSTRING_BEG;
24  test/ripper/test_parser_events.rb
@@ -755,12 +755,36 @@ def test_qwords_add
755 755
     assert_equal true, thru_qwords_add
756 756
   end
757 757
 
  758
+  def test_qsymbols_add
  759
+    thru_qsymbols_add = false
  760
+    parse('%i[a]', :on_qsymbols_add) {thru_qsymbols_add = true}
  761
+    assert_equal true, thru_qsymbols_add
  762
+  end
  763
+
  764
+  def test_symbols_add
  765
+    thru_symbols_add = false
  766
+    parse('%I[a]', :on_symbols_add) {thru_symbols_add = true}
  767
+    assert_equal true, thru_symbols_add
  768
+  end
  769
+
758 770
   def test_qwords_new
759 771
     thru_qwords_new = false
760 772
     parse('%w[]', :on_qwords_new) {thru_qwords_new = true}
761 773
     assert_equal true, thru_qwords_new
762 774
   end
763 775
 
  776
+  def test_qsymbols_new
  777
+    thru_qsymbols_new = false
  778
+    parse('%i[]', :on_qsymbols_new) {thru_qsymbols_new = true}
  779
+    assert_equal true, thru_qsymbols_new
  780
+  end
  781
+
  782
+  def test_symbols_new
  783
+    thru_symbols_new = false
  784
+    parse('%I[]', :on_symbols_new) {thru_symbols_new = true}
  785
+    assert_equal true, thru_symbols_new
  786
+  end
  787
+
764 788
   def test_redo
765 789
     thru_redo = false
766 790
     parse('redo', :on_redo) {thru_redo = true}
22  test/ripper/test_scanner_events.rb
@@ -608,6 +608,28 @@ def test_qwords_beg
608 608
                  scan('qwords_beg', '%w( w w w )')
609 609
   end
610 610
 
  611
+  def test_qsymbols_beg
  612
+    assert_equal [],
  613
+                 scan('qsymbols_beg', '')
  614
+    assert_equal ['%i('],
  615
+                 scan('qsymbols_beg', '%i()')
  616
+    assert_equal ['%i('],
  617
+                 scan('qsymbols_beg', '%i(w w w)')
  618
+    assert_equal ['%i( '],
  619
+                 scan('qsymbols_beg', '%i( w w w )')
  620
+  end
  621
+
  622
+  def test_symbols_beg
  623
+    assert_equal [],
  624
+                 scan('symbols_beg', '')
  625
+    assert_equal ['%I('],
  626
+                 scan('symbols_beg', '%I()')
  627
+    assert_equal ['%I('],
  628
+                 scan('symbols_beg', '%I(w w w)')
  629
+    assert_equal ['%I( '],
  630
+                 scan('symbols_beg', '%I( w w w )')
  631
+  end
  632
+
611 633
   # FIXME: Close paren must not present (`words_end' scanner event?).
612 634
   def test_words_sep
613 635
     assert_equal [],
11  test/ruby/test_array.rb
@@ -12,6 +12,17 @@ def teardown
12 12
     $VERBOSE = @verbose
13 13
   end
14 14
 
  15
+  def test_percent_i
  16
+    assert_equal([:foo, :bar], %i[foo bar])
  17
+    assert_equal([:"\"foo"], %i["foo])
  18
+  end
  19
+
  20
+  def test_percent_I
  21
+    x = 10
  22
+    assert_equal([:foo, :b10], %I[foo b#{x}])
  23
+    assert_equal([:"\"foo10"], %I["foo#{x}])
  24
+  end
  25
+
15 26
   def test_0_literal
16 27
     assert_equal([1, 2, 3, 4], [1, 2] + [3, 4])
17 28
     assert_equal([1, 2, 1, 2], [1, 2] * 2)

14 notes on commit 91bd6e7

Javier Saldana
jassa commented on 91bd6e7 July 26, 2012

nice feature! :+1:

Aliaxandr Rahalevich
saks commented on 91bd6e7 July 26, 2012

+1 for that!

Justin Baker

+1 pure winning.

Florian Frank
flori commented on 91bd6e7 July 26, 2012

Just discussed this in the team last week as a nice to have, and soon we have. Thx!

Mike Skalnik

:+1:. I've had this on my "Things To Do" list for a while. Guess I'll delete that now.

Evgeni Dzhelyov

Come on guys, you just complicated the language and forced every other implementation to implement that for having a syntax sugar for clearing list of symbols ....

EinLama

You should not bother about other implementations having a hard time to adapt - instead care about making life easier for people who actually write code using the language :)

+1 from me!

Evgeni Dzhelyov

Having a syntax sugar for writing arrays of symbols will not make your life easier as programmer, reducing the accidental and unneeded complexity will make it easier ... and Ruby is already cluttered and complex enough.

Julio Monteiro

:cool: that's a nice feature. That might not make the life easier for everybody, but it does for me.

Evgeni Dzhelyov

I will refer to the Rich Hickey talk - "Simple made easy" (http://www.infoq.com/presentations/Simple-Made-Easy).

Our job is to avoid the unnecessary complexity and provide simplistic, good solutions.
I urge the people behind big communities like Ruby, to acknowledge this and serve as role models for better and stop introducing needless complexity for the sake of "easier" life.

Eric Hodel
Collaborator

My only regret is that I will not be able to use this new syntax for a long time because ruby 1.9 does not support it… I can't wait!

Florian Frank

From my experience, simplicity is not a primary goal.
Seeking simplicity in language design does not help much, I think.

Because things too simple are difficult.
Because things too complex are difficult too.
Because human thoughts are not simple.
Because programs are essentially complex.
Because combination of simple concepts can be complex very easily.

-- Yukihiro Matsumoto, http://www.rubyist.net/~matz/slides/oscon2003/mgp00047.html

Saager Mhatre

I'm curious though, what would be a real world use case of this feature?

Evan Light

Good one, Josh!

Please sign in to comment.
Something went wrong with that request. Please try again.