Skip to content

Commit f169043

Browse files
committed
Add pipeline operator [Feature #15799]
1 parent e717d6f commit f169043

6 files changed

Lines changed: 47 additions & 1 deletion

File tree

NEWS

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ sufficient information, see the ChangeLog file or Redmine
4848
" # This has been warned since 2.4
4949
EOS
5050

51+
* Pipeline operator is added.
52+
53+
This code equals to the next code.
54+
55+
foo()
56+
|> bar 1, 2
57+
|> display
58+
59+
foo()
60+
.bar(1, 2)
61+
.display
62+
5163
=== Core classes updates (outstanding ones only)
5264

5365
Enumerable::

defs/id.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ token_ops = %[\
111111
OROP ||
112112
ANDDOT &.
113113
METHREF .:
114+
PIPE |>
114115
]
115116

116117
class KeywordError < RuntimeError

ext/ripper/eventids2.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ static const struct token_assoc {
262262
{tDSTAR, O(op)},
263263
{tANDDOT, O(op)},
264264
{tMETHREF, O(op)},
265+
{tPIPE, O(op)},
265266
{tSTRING_BEG, O(tstring_beg)},
266267
{tSTRING_CONTENT, O(tstring_content)},
267268
{tSTRING_DBEG, O(embexpr_beg)},

parse.y

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
10021002
%type <node> literal numeric simple_numeric ssym dsym symbol cpath
10031003
%type <node> top_compstmt top_stmts top_stmt begin_block
10041004
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
1005-
%type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr
1005+
%type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr pipeline
10061006
%type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure
10071007
%type <node> args call_args opt_call_args
10081008
%type <node> paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail
@@ -1060,6 +1060,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
10601060
%token <id> tANDDOT RUBY_TOKEN(ANDDOT) "&."
10611061
%token <id> tCOLON2 RUBY_TOKEN(COLON2) "::"
10621062
%token <id> tMETHREF RUBY_TOKEN(METHREF) ".:"
1063+
%token tPIPE RUBY_TOKEN(PIPE) "|>"
10631064
%token tCOLON3 ":: at EXPR_BEG"
10641065
%token <id> tOP_ASGN "operator-assignment" /* +=, -= etc. */
10651066
%token tASSOC "=>"
@@ -1095,6 +1096,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
10951096
%nonassoc modifier_if modifier_unless modifier_while modifier_until
10961097
%left keyword_or keyword_and
10971098
%right keyword_not
1099+
%left tPIPE
10981100
%nonassoc keyword_defined
10991101
%right '=' tOP_ASGN
11001102
%left modifier_rescue
@@ -2269,12 +2271,29 @@ arg : lhs '=' arg_rhs
22692271
/*% %*/
22702272
/*% ripper: ifop!($1, $3, $6) %*/
22712273
}
2274+
| pipeline
22722275
| primary
22732276
{
22742277
$$ = $1;
22752278
}
22762279
;
22772280

2281+
pipeline : arg tPIPE operation2 opt_paren_args
2282+
{
2283+
/*%%%*/
2284+
$$ = new_command_qcall(p, ID2VAL(idPIPE), $1, $3, $4, Qnull, &@3, &@$);
2285+
/*% %*/
2286+
/*% ripper: command_call!($1, ID2VAL(idPIPE), $3, $4) %*/
2287+
}
2288+
| arg tPIPE operation2 opt_paren_args brace_block
2289+
{
2290+
/*%%%*/
2291+
$$ = new_command_qcall(p, ID2VAL(idPIPE), $1, $3, $4, $5, &@3, &@$);
2292+
/*% %*/
2293+
/*% ripper: method_add_block!(command_call!($1, ID2VAL(idPIPE), $3, $4), $5) %*/
2294+
}
2295+
;
2296+
22782297
relop : '>' {$$ = '>';}
22792298
| '<' {$$ = '<';}
22802299
| tGEQ {$$ = idGE;}
@@ -8924,6 +8943,10 @@ parser_yylex(struct parser_params *p)
89248943
SET_LEX_STATE(EXPR_BEG);
89258944
return tOP_ASGN;
89268945
}
8946+
if (c == '>') {
8947+
SET_LEX_STATE(EXPR_DOT);
8948+
return tPIPE;
8949+
}
89278950
SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL);
89288951
pushback(p, c);
89298952
return '|';

test/ripper/test_scanner_events.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ def test_op
573573
scan('op', 'obj.:foo')
574574
assert_equal [],
575575
scan('op', %q[`make all`])
576+
assert_equal %w[|>],
577+
scan('op', %q[x|>y])
576578
end
577579

578580
def test_symbeg

test/ruby/test_syntax.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,13 @@ def test_numbered_parameter
13791379
assert_syntax_error('@1', /outside block/)
13801380
end
13811381

1382+
def test_pipeline_operator
1383+
assert_valid_syntax('x |> y')
1384+
x = nil
1385+
assert_equal("121", eval('x = 12 |> pow(2) |> to_s(11)'))
1386+
assert_equal(12, x)
1387+
end
1388+
13821389
private
13831390

13841391
def not_label(x) @result = x; @not_label ||= nil end

0 commit comments

Comments
 (0)