Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: opal/opal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 263205bb1d86
Choose a base ref
...
head repository: opal/opal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0713ebdfa290
Choose a head ref
  • 2 commits
  • 2 files changed
  • 2 contributors

Commits on Apr 4, 2015

  1. Copy the full SHA
    33727f7 View commit details
  2. Merge pull request #790 from vais/format

    Pass a few String#% specs and start cleaning up Kernel#format to pass more
    meh committed Apr 4, 2015
    Copy the full SHA
    0713ebd View commit details
Showing with 80 additions and 29 deletions.
  1. +80 −17 opal/corelib/kernel.rb
  2. +0 −12 spec/filters/bugs/string.rb
97 changes: 80 additions & 17 deletions opal/corelib/kernel.rb
Original file line number Diff line number Diff line change
@@ -174,129 +174,192 @@ def extend(*mods)
end

def format(format, *args)
if args.length == 1 && args[0].respond_to?(:to_ary)
args = args[0].to_ary
end

%x{
var idx = 0;
return format.replace(/%(\d+\$)?([-+ 0]*)(\d*|\*(\d+\$)?)(?:\.(\d*|\*(\d+\$)?))?([cspdiubBoxXfgeEG])|(%%)/g, function(str, idx_str, flags, width_str, w_idx_str, prec_str, p_idx_str, spec, escaped) {
var idx = 0,
idx_str = '([1-9]\\d*\\$)?',
flags = '([-+ 0]*)',
w_idx_str = '([1-9]\\d*\\$)?',
width_str = '(\\d*|\\*' + w_idx_str + ')',
p_idx_str = '([1-9]\\d*\\$)?',
prec_str = '(?:\\.(\\d*|\\*' + p_idx_str + '))?',
spec = '([cspdiubBoxXfgeEG])',
valid = '%' + idx_str + flags + width_str + prec_str + spec,
escaped = '(%%)',
invalid = '(%[^\\n\\0])';
return format.replace(new RegExp(valid + '|' + escaped + '|' + invalid, 'g'), function(str, idx_str, flags, width_str, w_idx_str, prec_str, p_idx_str, spec, escaped, invalid) {
if (escaped) {
return '%';
}
if (invalid) {
if (invalid.charAt(1) === ' ') {
#{raise ArgumentError, "invalid format character - %"}
}
else {
#{raise ArgumentError, "malformed format string - #{`invalid`}"}
}
}
var width,
prec,
is_integer_spec = ("diubBoxX".indexOf(spec) != -1),
is_float_spec = ("eEfgG".indexOf(spec) != -1),
prefix = '',
obj;
prec,
is_integer_spec = ("diubBoxX".indexOf(spec) != -1),
is_float_spec = ("eEfgG".indexOf(spec) != -1),
prefix = '',
obj;
if (width_str === undefined) {
width = undefined;
} else if (width_str.charAt(0) == '*') {
}
else if (width_str.charAt(0) == '*') {
var w_idx = idx++;
if (w_idx_str) {
w_idx = parseInt(w_idx_str, 10) - 1;
}
width = #{`args[w_idx]`.to_i};
} else {
}
else {
width = parseInt(width_str, 10);
}
if (!prec_str) {
prec = is_float_spec ? 6 : undefined;
} else if (prec_str.charAt(0) == '*') {
}
else if (prec_str.charAt(0) == '*') {
var p_idx = idx++;
if (p_idx_str) {
p_idx = parseInt(p_idx_str, 10) - 1;
}
prec = #{`args[p_idx]`.to_i};
} else {
}
else {
prec = parseInt(prec_str, 10);
}
if (idx_str) {
idx = parseInt(idx_str, 10) - 1;
}
switch (spec) {
case 'c':
obj = args[idx];
if (obj.$$is_string) {
str = obj.charAt(0);
} else {
str = String.fromCharCode(#{`obj`.to_i});
}
else if (#{`obj`.respond_to?(:to_str)}) {
str = #{`obj`.to_str}.charAt(0);
}
else if (#{`obj`.respond_to?(:to_ary)}) {
str = String.fromCharCode(#{`obj`.to_ary[0].to_int});
}
else {
str = String.fromCharCode(#{`obj`.to_int});
}
break;
case 's':
str = #{`args[idx]`.to_s};
if (prec !== undefined) {
str = str.substr(0, prec);
}
break;
case 'p':
str = #{`args[idx]`.inspect};
if (prec !== undefined) {
str = str.substr(0, prec);
}
break;
case 'd':
case 'i':
case 'u':
str = #{`args[idx]`.to_i}.toString();
break;
case 'b':
case 'B':
str = #{`args[idx]`.to_i}.toString(2);
break;
case 'o':
str = #{`args[idx]`.to_i}.toString(8);
break;
case 'x':
case 'X':
str = #{`args[idx]`.to_i}.toString(16);
break;
case 'e':
case 'E':
str = #{`args[idx]`.to_f}.toExponential(prec);
break;
case 'f':
str = #{`args[idx]`.to_f}.toFixed(prec);
break;
case 'g':
case 'G':
str = #{`args[idx]`.to_f}.toPrecision(prec);
break;
}
idx++;
if (is_integer_spec || is_float_spec) {
if (str.charAt(0) == '-') {
prefix = '-';
str = str.substr(1);
} else {
}
else {
if (flags.indexOf('+') != -1) {
prefix = '+';
} else if (flags.indexOf(' ') != -1) {
}
else if (flags.indexOf(' ') != -1) {
prefix = ' ';
}
}
}
if (is_integer_spec && prec !== undefined) {
if (str.length < prec) {
str = #{'0' * `prec - str.length`} + str;
}
}
var total_len = prefix.length + str.length;
if (width !== undefined && total_len < width) {
if (flags.indexOf('-') != -1) {
str = str + #{' ' * `width - total_len`};
} else {
}
else {
var pad_char = ' ';
if (flags.indexOf('0') != -1) {
str = #{'0' * `width - total_len`} + str;
} else {
}
else {
prefix = #{' ' * `width - total_len`} + prefix;
}
}
}
var result = prefix + str;
if ('XEG'.indexOf(spec) != -1) {
result = result.toUpperCase();
}
return result;
});
}
12 changes: 0 additions & 12 deletions spec/filters/bugs/string.rb
Original file line number Diff line number Diff line change
@@ -104,11 +104,8 @@
fails "String#to_r understands a forward slash as separating the numerator from the denominator"
fails "String#to_r returns (0/1) for Strings it can't parse"

fails "String#% raises an error if single % appears anywhere else"
fails "String#% raises an error if NULL or \\n appear anywhere else in the format string"
fails "String#% raises an ArgumentError for unused arguments when $DEBUG is true"
fails "String#% replaces trailing absolute argument specifier without type with percent sign"
fails "String#% raises an ArgumentError when given invalid argument specifiers"
fails "String#% raises an ArgumentError when multiple positional argument tokens are given for one format specifier"
fails "String#% raises an ArgumentError when multiple width star tokens are given for one format specifier"
fails "String#% raises an ArgumentError when a width star token is seen after a width token"
@@ -121,17 +118,13 @@
fails "String#% allows negative width to imply '-' flag"
fails "String#% ignores negative precision"
fails "String#% calls to_int on width star and precision star tokens"
fails "String#% tries to convert the argument to Array by calling #to_ary"
fails "String#% doesn't return subclass instances when called on a subclass"
fails "String#% always taints the result when the format string is tainted"
fails "String#% supports binary formats using %b for positive numbers"
fails "String#% supports binary formats using %b for negative numbers"
fails "String#% supports binary formats using %B with same behaviour as %b except for using 0B instead of 0b for #"
fails "String#% supports character formats using %c"
fails "String#% raises an exception for multiple character strings as argument for %c"
fails "String#% calls to_str on argument for %c formats"
fails "String#% calls #to_ary on argument for %c formats"
fails "String#% calls #to_int on argument for %c formats, if the argument does not respond to #to_ary"
fails "String#% supports float formats using %e"
fails "String#% supports float formats using %E"
fails "String#% pads with spaces for %E with Inf, -Inf, and NaN"
@@ -157,19 +150,14 @@
fails "String#% behaves as if calling Kernel#Integer for %u argument, if it does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Integer for %x argument, if it does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Integer for %X argument, if it does not respond to #to_ary"
fails "String#% tries to convert the passed argument to an Array using #to_ary"
fails "String#% behaves as if calling Kernel#Float for %e arguments, when the passed argument does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Float for %e arguments, when the passed argument is hexadecimal string"
fails "String#% tries to convert the passed argument to an Array using #to_ary"
fails "String#% behaves as if calling Kernel#Float for %E arguments, when the passed argument does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Float for %E arguments, when the passed argument is hexadecimal string"
fails "String#% tries to convert the passed argument to an Array using #to_ary"
fails "String#% behaves as if calling Kernel#Float for %f arguments, when the passed argument does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Float for %f arguments, when the passed argument is hexadecimal string"
fails "String#% tries to convert the passed argument to an Array using #to_ary"
fails "String#% behaves as if calling Kernel#Float for %g arguments, when the passed argument does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Float for %g arguments, when the passed argument is hexadecimal string"
fails "String#% tries to convert the passed argument to an Array using #to_ary"
fails "String#% behaves as if calling Kernel#Float for %G arguments, when the passed argument does not respond to #to_ary"
fails "String#% behaves as if calling Kernel#Float for %G arguments, when the passed argument is hexadecimal string"
fails "String#% when format string contains %{} sections replaces %{} sections with values from passed-in hash"