Socket
Socket
Sign inDemoInstall

@prettier/plugin-ruby

Package Overview
Dependencies
Maintainers
9
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@prettier/plugin-ruby - npm Package Compare versions

Comparing version 0.12.2 to 0.12.3

src/nodes/args.js

50

CHANGELOG.md

@@ -9,2 +9,49 @@ # Changelog

## [0.12.3] - 2019-05-16
### Changed
- [INTERNAL] Move arg, assign, constant, flow, massign, operator, scope, and statement nodes into their own files.
- [INTERNAL] Move `@int`, `access_ctrl`, `assocsplat`, `block_var`, `else`, `number_arg`, `super`, `undef`, `var_ref`, and `var_ref` as well as various call and symbol nodes into appropriate files.
- Better support for excessed commas in block args. Previously `proc { |x,| }` would add an extra space, but now it does not.
- [INTERNAL] Add a lot more documentation to the parser.
- Previously, the unary `not` operator inside a ternary (e.g., `a ? not(b) : c`) would break because it wouldn't add parentheses, but now it adds them. (Thanks to @glejeune for the report.)
- `if` and `unless` nodes used to not be able to handle if a comment was the only statement in the body. For example,
<!-- prettier-ignore -->
```ruby
if foo
# comment
end
```
would get printed as
<!-- prettier-ignore -->
```ruby
# comment if foo
```
Now the `if` and `unless` printers check for the presence of single comments.
- Fixes an error where `command` nodes within `def` nodes would fail to format if it was only a single block argument. For example,
<!-- prettier-ignore -->
```ruby
def curry(&block)
new &block
end
```
would fail, but now works. (Thanks to @JoshuaKGoldberg for the report.)
- Comments on lines with array references were previously deleting the array references entirely. For example,
<!-- prettier-ignore -->
```ruby
array[index] # comment
```
would previously result in `array[]`, but now prints properly. (Thanks to @xipgroc for the report.)
## [0.12.2] - 2019-04-30

@@ -338,3 +385,4 @@

[unreleased]: https://github.com/prettier/plugin-ruby/compare/v0.12.2...HEAD
[unreleased]: https://github.com/prettier/plugin-ruby/compare/v0.12.3...HEAD
[0.12.3]: https://github.com/prettier/plugin-ruby/compare/v0.12.2...v0.12.3
[0.12.2]: https://github.com/prettier/plugin-ruby/compare/v0.12.1...v0.12.2

@@ -341,0 +389,0 @@ [0.12.1]: https://github.com/prettier/plugin-ruby/compare/v0.12.0...v0.12.1

2

CONTRIBUTING.md

@@ -9,3 +9,3 @@ # Contributing

Your input Ruby code is parsed by Ripper, and pretty printed using the building blocks provided by Prettier. To ensure there are no regressions, Jest snapshots are used to keep track of the formatting before and after. Additionally there are Ruby tests written with Minitest to ensure there are no semantic regressions after the code has been tidied up.
Your input Ruby code is parsed by Ripper, and pretty printed using the building blocks provided by Prettier. Jest tests are used to protect against regressions and allow for test driving the development.

@@ -12,0 +12,0 @@ ## Ripper

{
"name": "@prettier/plugin-ruby",
"version": "0.12.2",
"version": "0.12.3",
"description": "prettier plugin for the Ruby programming language",

@@ -29,3 +29,3 @@ "main": "src/ruby.js",

"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^4.1.0",
"eslint-config-prettier": "^4.3.0",
"eslint-plugin-import": "^2.16.0",

@@ -32,0 +32,0 @@ "jest": "^24.0.0"

@@ -25,6 +25,4 @@ <div align="center">

`@prettier/plugin-ruby` is a [prettier](https://prettier.io/) plugin for the Ruby programming language. `prettier` is an opinionated code formatter that supports multiple languages and integrates with most editors. The idea is to eliminate discussions of style in code review and allow developers to get back to thinking about code design instead.
`@prettier/plugin-ruby` is a [prettier](https://prettier.io/) plugin for the Ruby programming language (versions `2.5` and above). `prettier` is an opinionated code formatter that supports multiple languages and integrates with most editors. The idea is to eliminate discussions of style in code review and allow developers to get back to thinking about code design instead.
Under the hood `@prettier/plugin-ruby` uses Ruby's own `ripper` library which allows this package to maintain parity with the existing Ruby parser. `@prettier/plugin-ruby` supports Ruby versions `2.5`, `2.6`, and `trunk`.
For example, the below [code segment](http://www.rubyinside.com/advent2006/4-ruby-obfuscation.html):

@@ -74,32 +72,50 @@

First, your system on which you're running is going to need a couple of things:
To run `prettier` with the Ruby plugin, you're going to need [`ruby`](https://www.ruby-lang.org/en/documentation/installation/) (version `2.5` or newer) and [`node`](https://nodejs.org/en/download/) (version `8.3` or newer). If you're integrating with a project that is not already using `prettier`, you should use the ruby gem. Otherwise you can use the `npm` package directly.
- [`ruby`](https://www.ruby-lang.org/en/documentation/installation/) `2.5` or newer - there are a lot of ways to install `ruby`, but I recommend [`rbenv`](https://github.com/rbenv/rbenv)
- [`node`](https://nodejs.org/en/download/) `8.3` or newer - `prettier` is a JavaScript package, so you're going to need to install `node` to work with it
- [`npm`](https://www.npmjs.com/get-npm) or [`yarn`](https://yarnpkg.com/en/docs/getting-started) - these are package managers for JavaScript, either one will do
### Ruby gem
Second, you're going to need to list `@prettier/plugin-ruby` as a JavaScript dependency from within whatever project on which you're working.
Add this line to your application's Gemfile:
If you do not already have a `package.json` file in the root of your repository, you can create one with:
```ruby
gem 'prettier'
```
And then execute:
```bash
echo '{ "name": "My Project" }' > package.json
bundle
```
After that you can add `prettier` and `@prettier/plugin-ruby` to your `package.json`'s `devDependencies` by running `npm install --save-dev prettier @prettier/plugin-ruby` if you are using `npm` or `yarn add --dev prettier @prettier/plugin-ruby` if you are using `yarn`.
Or install it yourself as:
Now, you can run `prettier` to tidy up your `ruby` files! Verify by running against one single file:
```bash
gem install prettier
```
The `rbprettier` executable is now installed and ready for use:
```bash
./node_modules/.bin/prettier --write path/to/file.rb
bundle exec rbprettier --write '**/*.rb'
```
If you're happy, you can can run `prettier` on an entire codebase:
### `npm` package
If you're using the `npm` CLI, then add the plugin by:
```bash
./node_modules/.bin/prettier --write '**/*.{rb,rake}'
npm install --save-dev prettier @prettier/plugin-ruby
```
Note that you can also install `prettier` globally with `npm install -g prettier @prettier/plugin-ruby` or you can add `./node_modules/.bin` to your `$PATH` so you don't need to reference the executable from the directory each time.
Or if you're using `yarn`, then add the plugin by:
```bash
yarn add --dev prettier @prettier/plugin-ruby
```
The `prettier` executable is now installed and ready for use:
```bash
./node_modules/.bin/prettier --write '**/*.rb'
```
## Configuration

@@ -132,3 +148,3 @@

```bash
./node_modules/.bin/prettier --prefer-single-quotes false --write '**/*.{rb,rake}'
prettier --prefer-single-quotes false --write '**/*.rb'
```

@@ -150,3 +166,3 @@

<!-- prettier-ignore -->
<table><tr><td align="center"><a href="https://kevindeisz.com"><img src="https://avatars2.githubusercontent.com/u/5093358?v=4" width="100px;" alt="Kevin Deisz"/><br /><sub><b>Kevin Deisz</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=kddeisz" title="Code">💻</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=kddeisz" title="Documentation">📖</a> <a href="#maintenance-kddeisz" title="Maintenance">🚧</a> <a href="#review-kddeisz" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=kddeisz" title="Tests">⚠️</a></td><td align="center"><a href="https://www.alanfoster.me/"><img src="https://avatars2.githubusercontent.com/u/1271782?v=4" width="100px;" alt="Alan Foster"/><br /><sub><b>Alan Foster</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=AlanFoster" title="Code">💻</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=AlanFoster" title="Documentation">📖</a> <a href="#review-AlanFoster" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=AlanFoster" title="Tests">⚠️</a></td><td align="center"><a href="https://github.com/johnschoeman"><img src="https://avatars0.githubusercontent.com/u/16049495?v=4" width="100px;" alt="johnschoeman"/><br /><sub><b>johnschoeman</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=johnschoeman" title="Tests">⚠️</a></td><td align="center"><a href="https://twitter.com/aaronjensen"><img src="https://avatars3.githubusercontent.com/u/8588?v=4" width="100px;" alt="Aaron Jensen"/><br /><sub><b>Aaron Jensen</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=aaronjensen" title="Documentation">📖</a></td><td align="center"><a href="http://cameronbothner.com"><img src="https://avatars1.githubusercontent.com/u/4642599?v=4" width="100px;" alt="Cameron Bothner"/><br /><sub><b>Cameron Bothner</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=cbothner" title="Code">💻</a></td><td align="center"><a href="https://localhost.dev"><img src="https://avatars3.githubusercontent.com/u/47308085?v=4" width="100px;" alt="localhost.dev"/><br /><sub><b>localhost.dev</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Alocalhostdotdev" title="Bug reports">🐛</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=localhostdotdev" title="Code">💻</a></td><td align="center"><a href="https://deecewan.github.io"><img src="https://avatars0.githubusercontent.com/u/4755785?v=4" width="100px;" alt="David Buchan-Swanson"/><br /><sub><b>David Buchan-Swanson</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Adeecewan" title="Bug reports">🐛</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=deecewan" title="Code">💻</a></td></tr><tr><td align="center"><a href="https://github.com/jpickwell"><img src="https://avatars1.githubusercontent.com/u/4682321?v=4" width="100px;" alt="Jordan Pickwell"/><br /><sub><b>Jordan Pickwell</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Ajpickwell" title="Bug reports">🐛</a></td><td align="center"><a href="http://codingitwrong.com"><img src="https://avatars0.githubusercontent.com/u/15832198?v=4" width="100px;" alt="Josh Justice"/><br /><sub><b>Josh Justice</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3ACodingItWrong" title="Bug reports">🐛</a></td><td align="center"><a href="https://github.com/xipgroc"><img src="https://avatars0.githubusercontent.com/u/28561131?v=4" width="100px;" alt="xipgroc"/><br /><sub><b>xipgroc</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Axipgroc" title="Bug reports">🐛</a></td></tr></table>
<table><tr><td align="center"><a href="https://kevindeisz.com"><img src="https://avatars2.githubusercontent.com/u/5093358?v=4" width="100px;" alt="Kevin Deisz"/><br /><sub><b>Kevin Deisz</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=kddeisz" title="Code">💻</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=kddeisz" title="Documentation">📖</a> <a href="#maintenance-kddeisz" title="Maintenance">🚧</a> <a href="#review-kddeisz" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=kddeisz" title="Tests">⚠️</a></td><td align="center"><a href="https://www.alanfoster.me/"><img src="https://avatars2.githubusercontent.com/u/1271782?v=4" width="100px;" alt="Alan Foster"/><br /><sub><b>Alan Foster</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=AlanFoster" title="Code">💻</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=AlanFoster" title="Documentation">📖</a> <a href="#review-AlanFoster" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=AlanFoster" title="Tests">⚠️</a></td><td align="center"><a href="https://github.com/johnschoeman"><img src="https://avatars0.githubusercontent.com/u/16049495?v=4" width="100px;" alt="johnschoeman"/><br /><sub><b>johnschoeman</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=johnschoeman" title="Tests">⚠️</a></td><td align="center"><a href="https://twitter.com/aaronjensen"><img src="https://avatars3.githubusercontent.com/u/8588?v=4" width="100px;" alt="Aaron Jensen"/><br /><sub><b>Aaron Jensen</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=aaronjensen" title="Documentation">📖</a></td><td align="center"><a href="http://cameronbothner.com"><img src="https://avatars1.githubusercontent.com/u/4642599?v=4" width="100px;" alt="Cameron Bothner"/><br /><sub><b>Cameron Bothner</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/commits?author=cbothner" title="Code">💻</a></td><td align="center"><a href="https://localhost.dev"><img src="https://avatars3.githubusercontent.com/u/47308085?v=4" width="100px;" alt="localhost.dev"/><br /><sub><b>localhost.dev</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Alocalhostdotdev" title="Bug reports">🐛</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=localhostdotdev" title="Code">💻</a></td><td align="center"><a href="https://deecewan.github.io"><img src="https://avatars0.githubusercontent.com/u/4755785?v=4" width="100px;" alt="David Buchan-Swanson"/><br /><sub><b>David Buchan-Swanson</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Adeecewan" title="Bug reports">🐛</a> <a href="https://github.com/kddeisz/plugin-ruby/commits?author=deecewan" title="Code">💻</a></td></tr><tr><td align="center"><a href="https://github.com/jpickwell"><img src="https://avatars1.githubusercontent.com/u/4682321?v=4" width="100px;" alt="Jordan Pickwell"/><br /><sub><b>Jordan Pickwell</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Ajpickwell" title="Bug reports">🐛</a></td><td align="center"><a href="http://codingitwrong.com"><img src="https://avatars0.githubusercontent.com/u/15832198?v=4" width="100px;" alt="Josh Justice"/><br /><sub><b>Josh Justice</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3ACodingItWrong" title="Bug reports">🐛</a></td><td align="center"><a href="https://github.com/xipgroc"><img src="https://avatars0.githubusercontent.com/u/28561131?v=4" width="100px;" alt="xipgroc"/><br /><sub><b>xipgroc</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Axipgroc" title="Bug reports">🐛</a></td><td align="center"><a href="http://lejeun.es"><img src="https://avatars1.githubusercontent.com/u/15168?v=4" width="100px;" alt="Gregoire Lejeune"/><br /><sub><b>Gregoire Lejeune</b></sub></a><br /><a href="https://github.com/kddeisz/plugin-ruby/issues?q=author%3Aglejeune" title="Bug reports">🐛</a></td></tr></table>

@@ -153,0 +169,0 @@ <!-- ALL-CONTRIBUTORS-LIST:END -->

@@ -1,579 +0,7 @@

const {
align,
breakParent,
concat,
dedent,
group,
hardline,
ifBreak,
indent,
join,
line,
literalline,
markAsRoot,
removeLines,
softline,
trim
} = require("./builders");
const toProc = require("./toProc");
const {
concatBody,
empty,
first,
literal,
makeArgs,
makeCall,
makeList,
prefix,
skipAssignIndent
} = require("./utils");
const nodes = {
"@int": (path, _opts, _print) => {
const { body } = path.getValue();
// If the number is octal and does not contain the optional "o" character
// after the leading 0, add it in.
if (/^0[0-9]/.test(body)) {
return `0o${body.slice(1)}`;
}
// If the number is a decimal number, is sufficiently large, and is not
// already formatted with underscores, then add them in in between the
// numbers every three characters starting from the right.
if (!body.startsWith("0") && body.length >= 4 && !body.includes("_")) {
return ` ${body}`
.slice((body.length + 2) % 3)
.match(/.{3}/g)
.join("_")
.trim();
}
return body;
},
"@__end__": (path, _opts, _print) => {
const { body } = path.getValue();
return concat([trim, "__END__", literalline, body]);
},
access_ctrl: first,
arg_paren: (path, opts, print) => {
if (path.getValue().body[0] === null) {
return "";
}
const { addTrailingCommas } = opts;
const { args, heredocs } = makeArgs(path, opts, print, 0);
const argsNode = path.getValue().body[0];
const hasBlock = argsNode.type === "args_add_block" && argsNode.body[1];
if (heredocs.length > 1) {
return concat(["(", join(", ", args), ")"].concat(heredocs));
}
const parenDoc = group(
concat([
"(",
indent(
concat([
softline,
join(concat([",", line]), args),
addTrailingCommas && !hasBlock ? ifBreak(",", "") : ""
])
),
concat([softline, ")"])
])
);
if (heredocs.length === 1) {
return group(concat([parenDoc].concat(heredocs)));
}
return parenDoc;
},
args: (path, opts, print) => {
const args = path.map(print, "body");
let blockNode = null;
[1, 2, 3].find(parent => {
const parentNode = path.getParentNode(parent);
blockNode =
parentNode &&
parentNode.type === "method_add_block" &&
parentNode.body[1];
return blockNode;
});
const proc = blockNode && toProc(blockNode);
if (proc) {
args.push(proc);
}
return args;
},
args_add_block: (path, opts, print) => {
const parts = path.call(print, "body", 0);
if (path.getValue().body[1]) {
parts.push(concat(["&", path.call(print, "body", 1)]));
}
return parts;
},
args_add_star: (path, opts, print) => {
const printed = path.map(print, "body");
const parts = printed[0]
.concat([concat(["*", printed[1]])])
.concat(printed.slice(2));
return parts;
},
assoc_splat: prefix("**"),
assign: (path, opts, print) => {
const [printedTarget, printedValue] = path.map(print, "body");
let adjustedValue = printedValue;
if (
["mrhs_add_star", "mrhs_new_from_args"].includes(
path.getValue().body[1].type
)
) {
adjustedValue = group(join(concat([",", line]), printedValue));
}
if (skipAssignIndent(path.getValue().body[1])) {
return group(concat([printedTarget, " = ", adjustedValue]));
}
return group(
concat([printedTarget, " =", indent(concat([line, adjustedValue]))])
);
},
assign_error: (_path, _opts, _print) => {
throw new Error("Can't set variable");
},
binary: (path, opts, print) => {
const operator = path.getValue().body[1];
const useNoSpace = operator === "**";
return group(
concat([
concat([path.call(print, "body", 0), useNoSpace ? "" : " "]),
operator,
indent(
concat([useNoSpace ? softline : line, path.call(print, "body", 2)])
)
])
);
},
block_var: (path, opts, print) => {
const parts = ["|", removeLines(path.call(print, "body", 0))];
// The second part of this node is a list of optional block-local variables
if (path.getValue().body[1]) {
parts.push("; ", join(", ", path.map(print, "body", 1)));
}
parts.push("| ");
return concat(parts);
},
blockarg: (path, opts, print) => concat(["&", path.call(print, "body", 0)]),
bodystmt: (path, opts, print) => {
const [_statements, rescue, elseClause, ensure] = path.getValue().body;
const parts = [path.call(print, "body", 0)];
if (rescue) {
parts.push(dedent(concat([hardline, path.call(print, "body", 1)])));
}
if (elseClause) {
// Before Ruby 2.6, this piece of bodystmt was an explicit "else" node
const stmts =
elseClause.type === "else"
? path.call(print, "body", 2, "body", 0)
: path.call(print, "body", 2);
parts.push(concat([dedent(concat([hardline, "else"])), hardline, stmts]));
}
if (ensure) {
parts.push(dedent(concat([hardline, path.call(print, "body", 3)])));
}
return group(concat(parts));
},
break: (path, opts, print) => {
const content = path.getValue().body[0];
if (content.body.length === 0) {
return "break";
}
if (content.body[0].body[0].type === "paren") {
return concat([
"break ",
path.call(print, "body", 0, "body", 0, "body", 0, "body", 0)
]);
}
return concat(["break ", join(", ", path.call(print, "body", 0))]);
},
class: (path, opts, print) => {
const [_constant, superclass, statements] = path.getValue().body;
const parts = ["class ", path.call(print, "body", 0)];
if (superclass) {
parts.push(" < ", path.call(print, "body", 1));
}
// If the body is empty, we can replace with a ;
const stmts = statements.body[0].body;
if (stmts.length === 1 && stmts[0].type === "void_stmt") {
return group(concat([concat(parts), ifBreak(line, "; "), "end"]));
}
return group(
concat([
concat(parts),
indent(concat([hardline, path.call(print, "body", 2)])),
concat([hardline, "end"])
])
);
},
class_name_error: (_path, _opts, _print) => {
throw new Error("class/module name must be CONSTANT");
},
const_path_field: (path, opts, print) => join("::", path.map(print, "body")),
const_path_ref: (path, opts, print) => join("::", path.map(print, "body")),
const_ref: first,
defined: (path, opts, print) =>
group(
concat([
"defined?(",
indent(concat([softline, path.call(print, "body", 0)])),
concat([softline, ")"])
])
),
dot2: (path, opts, print) =>
concat([
path.call(print, "body", 0),
"..",
path.getValue().body[1] ? path.call(print, "body", 1) : ""
]),
dot3: (path, opts, print) =>
concat([
path.call(print, "body", 0),
"...",
path.getValue().body[1] ? path.call(print, "body", 1) : ""
]),
dyna_symbol: (path, opts, print) => {
const { quote } = path.getValue().body[0];
return concat([":", quote, concat(path.call(print, "body", 0)), quote]);
},
else: (path, opts, print) => {
const stmts = path.getValue().body[0];
return concat([
stmts.body.length === 1 && stmts.body[0].type === "command"
? breakParent
: "",
"else",
indent(concat([softline, path.call(print, "body", 0)]))
]);
},
embdoc: (path, _opts, _print) => concat([trim, path.getValue().body]),
excessed_comma: empty,
fcall: concatBody,
field: (path, opts, print) =>
group(
concat([
path.call(print, "body", 0),
concat([makeCall(path, opts, print), path.call(print, "body", 2)])
])
),
massign: (path, opts, print) => {
let right = path.call(print, "body", 1);
if (
["mrhs_add_star", "mrhs_new_from_args"].includes(
path.getValue().body[1].type
)
) {
right = group(join(concat([",", line]), right));
}
return group(
concat([
group(join(concat([",", line]), path.call(print, "body", 0))),
" =",
indent(concat([line, right]))
])
);
},
method_add_arg: (path, opts, print) => {
const [method, args] = path.map(print, "body");
const argNode = path.getValue().body[1];
// This case will ONLY be hit if we can successfully turn the block into a
// to_proc call. In that case, we just explicitly add the parens around it.
if (argNode.type === "args" && args.length > 0) {
return concat([method, "("].concat(args).concat(")"));
}
return concat([method, args]);
},
method_add_block: (path, opts, print) => {
const [method, block] = path.getValue().body;
const proc = toProc(block);
if (proc && method.type === "call") {
return group(
concat([
path.call(print, "body", 0),
"(",
indent(concat([softline, proc])),
concat([softline, ")"])
])
);
}
if (proc) {
return path.call(print, "body", 0);
}
return concat(path.map(print, "body"));
},
methref: (path, opts, print) => join(".:", path.map(print, "body")),
mlhs: makeList,
mlhs_add_post: (path, opts, print) =>
path.call(print, "body", 0).concat(path.call(print, "body", 1)),
mlhs_add_star: (path, opts, print) =>
path
.call(print, "body", 0)
.concat([
path.getValue().body[1]
? concat(["*", path.call(print, "body", 1)])
: "*"
]),
mlhs_paren: (path, opts, print) => {
if (["massign", "mlhs_paren"].includes(path.getParentNode().type)) {
// If we're nested in brackets as part of the left hand side of an
// assignment, i.e., (a, b, c) = 1, 2, 3
// ignore the current node and just go straight to the content
return path.call(print, "body", 0);
}
return group(
concat([
"(",
indent(
concat([
softline,
join(concat([",", line]), path.call(print, "body", 0))
])
),
concat([softline, ")"])
])
);
},
mrhs: makeList,
mrhs_add_star: (path, opts, print) =>
path
.call(print, "body", 0)
.concat([concat(["*", path.call(print, "body", 1)])]),
mrhs_new_from_args: (path, opts, print) => {
const parts = path.call(print, "body", 0);
if (path.getValue().body.length > 1) {
parts.push(path.call(print, "body", 1));
}
return parts;
},
module: (path, opts, print) => {
const declaration = group(concat(["module ", path.call(print, "body", 0)]));
// If the body is empty, we can replace with a ;
const stmts = path.getValue().body[1].body[0].body;
if (stmts.length === 1 && stmts[0].type === "void_stmt") {
return group(concat([declaration, ifBreak(line, "; "), "end"]));
}
return group(
concat([
declaration,
indent(concat([hardline, path.call(print, "body", 1)])),
concat([hardline, "end"])
])
);
},
next: (path, opts, print) => {
const args = path.getValue().body[0].body[0];
if (!args) {
return "next";
}
if (args.body[0].type === "paren") {
// Ignoring the parens node and just going straight to the content
return concat([
"next ",
path.call(print, "body", 0, "body", 0, "body", 0, "body", 0)
]);
}
return concat(["next ", join(", ", path.call(print, "body", 0))]);
},
number_arg: first,
opassign: (path, opts, print) =>
group(
concat([
path.call(print, "body", 0),
" ",
path.call(print, "body", 1),
indent(concat([line, path.call(print, "body", 2)]))
])
),
paren: (path, opts, print) => {
if (!path.getValue().body[0]) {
return "()";
}
let content = path.call(print, "body", 0);
if (
["args", "args_add_star", "args_add_block"].includes(
path.getValue().body[0].type
)
) {
content = join(concat([",", line]), content);
}
return group(
concat([
"(",
indent(concat([softline, content])),
concat([softline, ")"])
])
);
},
program: (path, opts, print) =>
markAsRoot(
concat([join(literalline, path.map(print, "body")), literalline])
),
return: (path, opts, print) => {
const args = path.getValue().body[0].body[0];
if (!args) {
return "return";
}
if (args.body[0] && args.body[0].type === "paren") {
// Ignoring the parens node and just going straight to the content
return concat([
"return ",
path.call(print, "body", 0, "body", 0, "body", 0, "body", 0)
]);
}
return concat(["return ", join(", ", path.call(print, "body", 0))]);
},
return0: literal("return"),
sclass: (path, opts, print) =>
group(
concat([
concat(["class << ", path.call(print, "body", 0)]),
indent(concat([hardline, path.call(print, "body", 1)])),
concat([hardline, "end"])
])
),
stmts: (path, opts, print) => {
const stmts = path.getValue().body;
const parts = [];
let lineNo = null;
stmts.forEach((stmt, index) => {
if (stmt.type === "void_stmt") {
return;
}
const printed = path.call(print, "body", index);
if (lineNo === null) {
parts.push(printed);
} else if (
stmt.start - lineNo > 1 ||
[stmt.type, stmts[index - 1].type].includes("access_ctrl")
) {
parts.push(hardline, hardline, printed);
} else if (
stmt.start !== lineNo ||
path.getParentNode().type !== "string_embexpr"
) {
parts.push(hardline, printed);
} else {
parts.push("; ", printed);
}
lineNo = stmt.end;
});
return concat(parts);
},
super: (path, opts, print) => {
const args = path.getValue().body[0];
if (args.type === "arg_paren") {
// In case there are explicitly no arguments but they are using parens,
// we assume they are attempting to override the initializer and pass no
// arguments up.
if (args.body[0] === null) {
return "super()";
}
return concat(["super", path.call(print, "body", 0)]);
}
return concat(["super ", join(", ", path.call(print, "body", 0))]);
},
symbol: prefix(":"),
symbol_literal: concatBody,
top_const_field: prefix("::"),
top_const_ref: prefix("::"),
unary: (path, opts, print) => {
const operator = path.getValue().body[0];
return concat([
operator === "not" ? "not " : operator[0],
path.call(print, "body", 1)
]);
},
undef: (path, opts, print) =>
group(
concat([
"undef ",
align(
"undef ".length,
join(concat([",", line]), path.map(print, "body", 0))
)
])
),
var_field: concatBody,
var_ref: first,
vcall: first,
yield: (path, opts, print) => {
if (path.getValue().body[0].type === "paren") {
return concat(["yield", path.call(print, "body", 0)]);
}
return concat(["yield ", join(", ", path.call(print, "body", 0))]);
},
yield0: literal("yield"),
zsuper: literal("super")
};
module.exports = Object.assign(
{},
require("./nodes/alias"),
require("./nodes/args"),
require("./nodes/arrays"),
require("./nodes/assign"),
require("./nodes/blocks"),

@@ -584,12 +12,18 @@ require("./nodes/calls"),

require("./nodes/conditionals"),
require("./nodes/constants"),
require("./nodes/flow"),
require("./nodes/hashes"),
require("./nodes/hooks"),
require("./nodes/ints"),
require("./nodes/lambdas"),
require("./nodes/loops"),
require("./nodes/massign"),
require("./nodes/methods"),
require("./nodes/operators"),
require("./nodes/params"),
require("./nodes/regexp"),
require("./nodes/rescue"),
require("./nodes/strings"),
nodes
require("./nodes/scopes"),
require("./nodes/statements"),
require("./nodes/strings")
);

@@ -1,2 +0,2 @@

const { concat, join } = require("../builders");
const { concat, join } = require("../prettier");

@@ -3,0 +3,0 @@ const usingSymbols = path => {

@@ -10,3 +10,3 @@ const {

softline
} = require("../builders");
} = require("../prettier");

@@ -13,0 +13,0 @@ const isStringArray = args =>

@@ -7,5 +7,7 @@ const {

indent,
join,
removeLines,
softline
} = require("../builders");
const { hasAncestor } = require("../utils");
} = require("../prettier");
const { empty, first, hasAncestor } = require("../utils");

@@ -65,4 +67,17 @@ const printBlock = (path, opts, print) => {

module.exports = {
block_var: (path, opts, print) => {
const parts = ["|", removeLines(path.call(print, "body", 0))];
// The second part of this node is a list of optional block-local variables
if (path.getValue().body[1]) {
parts.push("; ", join(", ", path.map(print, "body", 1)));
}
parts.push("| ");
return concat(parts);
},
brace_block: printBlock,
do_block: printBlock
do_block: printBlock,
excessed_comma: empty,
number_arg: first
};

@@ -1,3 +0,4 @@

const { concat, group, indent, softline } = require("../builders");
const { makeCall } = require("../utils");
const { concat, group, indent, softline } = require("../prettier");
const toProc = require("../toProc");
const { concatBody, first, makeCall } = require("../utils");

@@ -27,3 +28,36 @@ const noIndent = ["array", "hash", "method_add_block", "xstring_literal"];

);
}
},
fcall: concatBody,
method_add_arg: (path, opts, print) => {
const [method, args] = path.map(print, "body");
const argNode = path.getValue().body[1];
// This case will ONLY be hit if we can successfully turn the block into a
// to_proc call. In that case, we just explicitly add the parens around it.
if (argNode.type === "args" && args.length > 0) {
return concat([method, "("].concat(args).concat(")"));
}
return concat([method, args]);
},
method_add_block: (path, opts, print) => {
const [method, block] = path.getValue().body;
const proc = toProc(block);
if (proc && method.type === "call") {
return group(
concat([
path.call(print, "body", 0),
"(",
indent(concat([softline, proc])),
concat([softline, ")"])
])
);
}
if (proc) {
return path.call(print, "body", 0);
}
return concat(path.map(print, "body"));
},
vcall: first
};

@@ -9,3 +9,3 @@ const {

line
} = require("../builders");
} = require("../prettier");

@@ -12,0 +12,0 @@ module.exports = {

@@ -1,2 +0,2 @@

const { align, concat, group, ifBreak, join, line } = require("../builders");
const { align, concat, group, ifBreak, join, line } = require("../prettier");
const { docLength, makeArgs, makeCall } = require("../utils");

@@ -7,2 +7,3 @@

node.body[1].body[0].type === "args" &&
node.body[1].body[0].body[0] &&
node.body[1].body[0].body[0].type === "def";

@@ -9,0 +10,0 @@

@@ -10,3 +10,3 @@ const {

softline
} = require("../builders");
} = require("../prettier");

@@ -51,45 +51,110 @@ const noTernary = [

const printTernaryConditions = (keyword, truthyValue, falsyValue) => {
const parts = [truthyValue, " : ", falsyValue];
// For the unary `not` operator, we need to explicitly add parentheses to it in
// order for it to be valid from within a ternary. Otherwise if the clause of
// the ternary isn't a unary `not`, we can just pass it along.
const printTernaryClause = clause => {
if (clause.type === "concat") {
const [part] = clause.parts;
if (part.type === "concat" && part.parts[0] === "not") {
// We are inside of a statements list and the statement is a unary `not`.
return concat(["not(", part.parts[2], ")"]);
}
if (clause.parts[0] === "not") {
// We are inside a ternary condition and the clause is a unary `not`.
return concat(["not(", clause.parts[2], ")"]);
}
}
return clause;
};
// The conditions for a ternary look like `foo : bar` where `foo` represents
// the truthy clause and `bar` represents the falsy clause. In the case that the
// parent node is an `unless`, these have to flip in order.
const printTernaryClauses = (keyword, truthyClause, falsyClause) => {
const parts = [
printTernaryClause(truthyClause),
" : ",
printTernaryClause(falsyClause)
];
return keyword === "if" ? parts : parts.reverse();
};
const canTernary = stmts =>
stmts.body.length === 1 && !noTernary.includes(stmts.body[0].type);
// Handles ternary nodes. If it does not fit on one line, then we break out into
// an if/else statement. Otherwise we remain as a ternary.
const printTernary = (path, _opts, print) => {
const [predicate, truthyClause, falsyClause] = path.map(print, "body");
const ternaryClauses = printTernaryClauses("if", truthyClause, falsyClause);
const printConditional = keyword => (path, { inlineConditionals }, print) => {
const [_predicate, stmts, addition] = path.getValue().body;
return group(
ifBreak(
concat([
"if ",
predicate,
indent(concat([softline, truthyClause])),
concat([softline, "else"]),
indent(concat([softline, falsyClause])),
concat([softline, "end"])
]),
concat([predicate, " ? "].concat(ternaryClauses))
)
);
};
// If the addition is not an elsif or an else, then it's the second half of a
// ternary expression
if (addition && addition.type !== "elsif" && addition.type !== "else") {
const parts = [path.call(print, "body", 0), " ? "];
const truthyValue = path.call(print, "body", 1);
const falsyValue = path.call(print, "body", 2);
// Prints an `if_mod` or `unless_mod` node. Because it was previously in the
// modifier form, we're guaranteed to not have an additional node, so we can
// just work with the predicate and the body.
const printSingle = keyword => (path, { inlineConditionals }, print) => {
const multiline = concat([
`${keyword} `,
align(keyword.length - 1, path.call(print, "body", 0)),
indent(concat([softline, path.call(print, "body", 1)])),
concat([softline, "end"])
]);
return group(
ifBreak(
concat([
`${keyword} `,
path.call(print, "body", 0),
indent(concat([softline, path.call(print, "body", 1)])),
concat([softline, "else"]),
indent(concat([softline, path.call(print, "body", 2)])),
concat([softline, "end"])
]),
concat(
parts.concat(printTernaryConditions(keyword, truthyValue, falsyValue))
)
)
);
const stmts = path.getValue().body[1];
const hasComments =
stmts.type === "stmts" && stmts.body.some(stmt => stmt.type === "@comment");
if (!inlineConditionals || hasComments) {
return multiline;
}
// If there is an else and only an else, attempt to shorten to a ternary
if (
const inline = concat([
path.call(print, "body", 1),
` ${keyword} `,
path.call(print, "body", 0)
]);
return group(ifBreak(multiline, inline));
};
// Certain expressions cannot be reduced to a ternary without adding parens
// around them. In this case we say they cannot be ternaried and default instead
// to breaking them into multiple lines.
const canTernaryStmts = stmts =>
stmts.body.length === 1 && !noTernary.includes(stmts.body[0].type);
// In order for an `if` or `unless` expression to be shortened to a ternary,
// there has to be one and only one "addition" (another clause attached) which
// is of the "else" type. Both the body of the main node and the body of the
// additional node must have only one statement, and that statement list must
// pass the `canTernaryStmts` check.
const canTernary = path => {
const [_pred, stmts, addition] = path.getValue().body;
return (
addition &&
addition.type === "else" &&
canTernary(stmts) &&
canTernary(addition.body[0])
) {
const ternary = printTernaryConditions(
[stmts, addition.body[0]].every(canTernaryStmts)
);
};
// A normalized print function for both `if` and `unless` nodes.
const printConditional = keyword => (path, { inlineConditionals }, print) => {
if (canTernary(path)) {
const ternaryConditions = printTernaryClauses(
keyword,

@@ -103,3 +168,3 @@ path.call(print, "body", 1),

printWithAddition(keyword, path, print),
concat([path.call(print, "body", 0), " ? "].concat(ternary))
concat([path.call(print, "body", 0), " ? "].concat(ternaryConditions))
)

@@ -109,27 +174,23 @@ );

// If there's an additional clause, we know we can't go for the inline option
if (addition) {
// If there's an additional clause that wasn't matched earlier, we know we
// can't go for the inline option.
if (path.getValue().body[2]) {
return group(printWithAddition(keyword, path, print, { breaking: true }));
}
// If it's short enough, favor the inline conditional
return group(
ifBreak(
concat([
`${keyword} `,
align(keyword.length - 1, path.call(print, "body", 0)),
indent(concat([softline, path.call(print, "body", 1)])),
concat([softline, "end"])
]),
concat([
inlineConditionals ? "" : breakParent,
path.call(print, "body", 1),
` ${keyword} `,
path.call(print, "body", 0)
])
)
);
return printSingle(keyword)(path, { inlineConditionals }, print);
};
module.exports = {
else: (path, opts, print) => {
const stmts = path.getValue().body[0];
return concat([
stmts.body.length === 1 && stmts.body[0].type === "command"
? breakParent
: "",
"else",
indent(concat([softline, path.call(print, "body", 0)]))
]);
},
elsif: (path, opts, print) => {

@@ -154,6 +215,6 @@ const [_predicate, _statements, addition] = path.getValue().body;

if: printConditional("if"),
ifop: printConditional("if"),
if_mod: printConditional("if"),
ifop: printTernary,
if_mod: printSingle("if"),
unless: printConditional("unless"),
unless_mod: printConditional("unless")
unless_mod: printSingle("unless")
};

@@ -9,4 +9,4 @@ const {

literalline
} = require("../builders");
const { skipAssignIndent } = require("../utils");
} = require("../prettier");
const { prefix, skipAssignIndent } = require("../utils");

@@ -71,2 +71,3 @@ const nodeDive = (node, steps) => {

},
assoc_splat: prefix("**"),
assoclist_from_args: (path, opts, print) => {

@@ -73,0 +74,0 @@ const { addTrailingCommas } = opts;

@@ -1,2 +0,2 @@

const { concat, group, indent, line } = require("../builders");
const { concat, group, indent, line } = require("../prettier");

@@ -3,0 +3,0 @@ const printHook = name => (path, opts, print) =>

@@ -9,3 +9,3 @@ const {

softline
} = require("../builders");
} = require("../prettier");
const { hasAncestor } = require("../utils");

@@ -12,0 +12,0 @@

@@ -9,3 +9,3 @@ const {

softline
} = require("../builders");
} = require("../prettier");

@@ -12,0 +12,0 @@ const printLoop = keyword => (path, { inlineLoops }, print) =>

@@ -1,2 +0,11 @@

const { concat, group, hardline, indent } = require("../builders");
const {
align,
concat,
group,
hardline,
indent,
join,
line
} = require("../prettier");
const { first, literal } = require("../utils");

@@ -40,4 +49,33 @@ const printMethod = offset => (path, opts, print) => {

module.exports = {
access_ctrl: first,
def: printMethod(0),
defs: printMethod(2)
defs: printMethod(2),
methref: (path, opts, print) => join(".:", path.map(print, "body")),
super: (path, opts, print) => {
const args = path.getValue().body[0];
if (args.type === "arg_paren") {
// In case there are explicitly no arguments but they are using parens,
// we assume they are attempting to override the initializer and pass no
// arguments up.
if (args.body[0] === null) {
return "super()";
}
return concat(["super", path.call(print, "body", 0)]);
}
return concat(["super ", join(", ", path.call(print, "body", 0))]);
},
undef: (path, opts, print) =>
group(
concat([
"undef ",
align(
"undef ".length,
join(concat([",", line]), path.map(print, "body", 0))
)
])
),
zsuper: literal("super")
};

@@ -1,2 +0,2 @@

const { concat, group, join, line } = require("../builders");
const { concat, group, join, line } = require("../prettier");

@@ -36,3 +36,3 @@ const printGenericRestParam = symbol => (path, opts, print) =>

if (rest) {
if (rest && rest.type !== "excessed_comma") {
parts.push(path.call(print, "body", 2));

@@ -64,3 +64,14 @@ }

return group(join(concat([",", line]), parts));
// You can put an extra comma at the end of block args between pipes to
// change what it does. Below is the difference:
//
// [[1, 2], [3, 4]].each { |x| p x } # prints [1, 2] then [3, 4]
// [[1, 2], [3, 4]].each { |x,| p x } # prints 1 then 3
//
// In ruby 2.5, the excessed comma is indicated by having a 0 in the rest
// param position. In ruby 2.6+ it's indicated by having an "excessed_comma"
// node in the rest position. Seems odd, but it's true.
const comma = rest === 0 || (rest && rest.type === "excessed_comma");
return group(concat([join(concat([",", line]), parts), comma ? "," : ""]));
};

@@ -67,0 +78,0 @@

@@ -1,2 +0,2 @@

const { concat } = require("../builders");
const { concat } = require("../prettier");
const { makeList } = require("../utils");

@@ -3,0 +3,0 @@

@@ -9,3 +9,3 @@ const {

line
} = require("../builders");
} = require("../prettier");
const { literal } = require("../utils");

@@ -12,0 +12,0 @@

@@ -9,4 +9,4 @@ const {

softline
} = require("../builders");
const { concatBody, empty, makeList, surround } = require("../utils");
} = require("../prettier");
const { concatBody, empty, makeList, prefix, surround } = require("../utils");
const escapePattern = require("../escapePattern");

@@ -76,2 +76,7 @@

},
dyna_symbol: (path, opts, print) => {
const { quote } = path.getValue().body[0];
return concat([":", quote, concat(path.call(print, "body", 0)), quote]);
},
heredoc: (path, opts, print) => {

@@ -134,2 +139,4 @@ const { beging, ending } = path.getValue();

},
symbol: prefix(":"),
symbol_literal: concatBody,
word_add: concatBody,

@@ -136,0 +143,0 @@ word_new: empty,

@@ -7,3 +7,3 @@ const {

literalline
} = require("./builders");
} = require("./prettier");

@@ -10,0 +10,0 @@ const concatBody = (path, opts, print) => concat(path.map(print, "body"));

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc