diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 00000000..64ccf7a7 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,54 @@ +version: "2" + +checks: + argument-count: + config: + threshold: 4 + complex-logic: + config: + threshold: 10 + file-lines: + config: + threshold: 1000 + method-complexity: + config: + threshold: 5 + method-count: + config: + threshold: 100 + method-lines: + config: + threshold: 30 + nested-control-flow: + config: + threshold: 4 + return-statements: + config: + threshold: 4 + # similar-code: + # config: + # threshold: # language-specific defaults. an override will affect all languages. + # identical-code: + # config: + # threshold: # language-specific defaults. an override will affect all languages. + +plugins: + rubocop: + enabled: true + channel: rubocop-0-53 + +exclude_patterns: + - "benchmark/*" + - "benchmark-ips/*" + - "build/*" + - "coverage/*" + - "docs/*" + - "examples/*" + - "tasks/*" + - "spec/*" + - "test/*" + - "vendored-minitest/*" + - "**/node_modules/*" + - stdlib/nodejs/js-yaml-3-6-1.js + - lib/opal/source_map/vlq.rb + - lib/opal/cli_runners/source-map-support*.js diff --git a/.eslintrc.await.js b/.eslintrc.await.js new file mode 100644 index 00000000..31192248 --- /dev/null +++ b/.eslintrc.await.js @@ -0,0 +1,6 @@ +module.exports = { + "extends": "./.eslintrc.js", + "parserOptions": { + "ecmaVersion": 8 + }, +}; diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..b8b7dda6 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,35 @@ +module.exports = { + "env": { + "browser": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 3 + }, + "rules": { + "no-unused-vars": ["error", { + "varsIgnorePattern": "(\$(\$|\$\$|yield|post_args|[a-z])|self)", + "argsIgnorePattern": "(\$(\$|\$\$|yield|post_args|[a-z])|self)", + }], + "no-extra-semi": "off", + "no-empty": "off", + "no-unreachable": "off", + "no-cond-assign": "off", + "no-prototype-builtins": "off", + "no-constant-condition": ["error", { "checkLoops": false }], + "no-useless-escape": "off", + "no-fallthrough": ["error", { "commentPattern": "raise|no-break" }], + "no-regex-spaces": "off", + "no-control-regex": "off", + }, + "globals": { + "Opal": "readonly", + "DataView": "readonly", + "ArrayBuffer": "readonly", + "globalThis": "readonly", + "Uint8Array": "readonly", + "Promise": "readonly", + "WeakRef": "readonly", + } +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..e69c0d85 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +UNRELEASED.md merge=union diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..c3dba81d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: opal diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 00000000..16c08602 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,47 @@ +--- +name: Bug report +about: Create a report to help us improve +title: 'Bug: ' +labels: bug +assignees: '' + +--- + +**Describe the bug** + + +Opal version: … + + +**To Reproduce** + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..01e9bb27 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: 'Feature: ' +labels: feature +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..fb0d317c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,105 @@ +name: build + +on: + push: + branches: + - master + - "*-stable" + - "*/ci-check" + pull_request: {} + +jobs: + rake: + name: ${{ matrix.combo.name || matrix.combo.ruby }} + strategy: + fail-fast: false + matrix: + combo: + - name: mspec-nodejs + ruby: '3.0' + command: bin/rake mspec_nodejs + - name: mspec-chrome + ruby: '3.0' + command: bin/rake mspec_chrome + - name: minitest + ruby: '3.0' + command: bin/rake minitest + - name: minitest-strict-mode + ruby: '3.0' + command: bin/rake minitest + strict: 'true' + - name: head-ruby + ruby: head + permissive: true + - name: current-ruby + ruby: 3.1 + - name: previous-ruby + ruby: '3.0' + - name: older-ruby + ruby: 2.7 + - name: near-eol-ruby + ruby: 2.6 + - name: smoke-test + ruby: '3.0' + command: bin/rake smoke_test + - name: windows + # These two fail because of broken stacktraces on windows: minitest_node_nodejs mspec_nodejs + command: bundle exec rake rspec minitest_nodejs + ruby: '3.0' + os: windows-latest + - name: lint + command: bin/rake lint + ruby: '3.0' + - name: timezone + ruby: '3.0' + - name: performance + ruby: '3.0' + permissive: true + fetchdepth: '0' + command: bin/rake performance:compare + os: ryzen + + # Currently failing: + # - ruby: truffleruby + # - ruby: jruby + + runs-on: ${{ matrix.combo.os || 'ubuntu-latest' }} + continue-on-error: ${{ matrix.combo.permissive || false }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: ${{ fromJSON(matrix.combo.fetchdepth || '1') }} + - if: ${{ matrix.combo.os != 'ryzen' }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.combo.ruby }} + bundler-cache: false + - run: ruby bin/git-submodule-fast-install + - run: bundle lock + - uses: actions/cache@v2 + with: + path: ./vendor/bundle + key: ${{ runner.os }}-${{ matrix.combo.ruby }}-gem-${{ github.ref }}-${{ hashFiles('**/Gemfile.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.combo.ruby }}-gem-${{ github.ref }} + ${{ runner.os }}-${{ matrix.combo.ruby }}-gem-master + ${{ runner.os }}-${{ matrix.combo.ruby }}-gem- + - uses: actions/cache@v2 + with: + path: ./node_modules + key: ${{ runner.os }}-npm-${{ github.ref }}-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-npm-${{ github.ref }} + ${{ runner.os }}-npm-master + ${{ runner.os }}-npm- + - run: yarn install + - name: bundle install + run: | + bundle config path $PWD/vendor/bundle + bundle install --jobs 4 --retry 3 + bundle clean + - name: set environment variables + if: ${{ matrix.combo.strict == 'true' }} + run: | + echo "USE_STRICT=true" >> $GITHUB_ENV + - run: ${{ matrix.combo.command || 'bin/rake rspec' }} diff --git a/.gitignore b/.gitignore index ceeb05b4..a529e264 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,21 @@ +.DS_Store +*.gem +.yardoc +.bundle +Gemfile.lock +Gemfile.local +build/ +/.github_access_token +/cdn +/node_modules +/gh-pages /tmp +.ruby-gemset +.ruby-version +.rvmrc +.rspec-local +/coverage + +# Ignore old submodules, useful when switching branches +spec/corelib +spec/rubyspec diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..19a41785 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,10 @@ +[submodule "spec/ruby"] + path = spec/ruby + url = https://github.com/ruby/spec.git +[submodule "test/cruby"] + path = test/cruby + url = https://github.com/ruby/ruby.git + branch = ruby_2_2 +[submodule "spec/mspec"] + path = spec/mspec + url = https://github.com/ruby/mspec.git diff --git a/.inch.yml b/.inch.yml new file mode 100644 index 00000000..46d9d703 --- /dev/null +++ b/.inch.yml @@ -0,0 +1,19 @@ +# files: +# # define files included in the analysis (defaults to ["{app,lib}/**/*.rb"]) +# included: +# - plugins/**/*.rb +# # define files excluded from the analysis (defaults to []) +# excluded: +# # you can use file paths +# - plugins/vendor/sparkr/sparkr.rb +# # or globs +# - plugins/vendor/**/*.rb +# # or regular expressions +# - !ruby/regexp /vendor/ + + +files: + included: + - lib/**/*.rb + excluded: + - lib/opal/parser/grammar.rb diff --git a/.overcommit.yml b/.overcommit.yml new file mode 100644 index 00000000..5910361a --- /dev/null +++ b/.overcommit.yml @@ -0,0 +1,35 @@ +# Use this file to configure the Overcommit hooks you wish to use. This will +# extend the default configuration defined in: +# https://github.com/sds/overcommit/blob/master/config/default.yml +# +# At the topmost level of this YAML file is a key representing type of hook +# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can +# customize each hook, such as whether to only run it on certain files (via +# `include`), whether to only display output if it fails (via `quiet`), etc. +# +# For a complete list of hooks, see: +# https://github.com/sds/overcommit/tree/master/lib/overcommit/hook +# +# For a complete list of options that you can use to customize hooks, see: +# https://github.com/sds/overcommit#configuration +# +# Uncomment the following lines to make the configuration take effect. + +gemfile: Gemfile + +PreCommit: + RuboCop: + enabled: true + on_warn: fail # Treat all warnings as failures + + TrailingWhitespace: + enabled: true + # exclude: + # - '**/db/structure.sql' # Ignore trailing whitespace in generated files + +#PostCheckout: +# ALL: # Special hook name that customizes all hooks of this type +# quiet: true # Change all post-checkout hooks to only display output on failure +# +# IndexTags: +# enabled: true # Generate a tags file with `ctags` each time HEAD changes diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..ba601fd1 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require lib/spec_helper diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..f4c06922 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,450 @@ +require: rubocop-performance +inherit_from: .rubocop/todo.yml + +AllCops: + TargetRubyVersion: 2.6 + Exclude: + - CHANGELOG.md + - CONDUCT.md + - CONTRIBUTING.md + - Gemfile/**/* + - Gemfile.lock + - Guardfile/**/* + - HACKING.md + - LICENSE/**/* + - README.md + - Rakefile/**/* + - '*' + - __* + - __*/**/* + - appveyor.yml + - benchmark/**/* + - benchmark-ips/**/* + - bin/**/* + - build/**/* + - config.ru + - coverage/**/* + - docs/**/* + - examples/**/* + - exe/**/* + # - lib/**/* + - lib/opal/source_map/vlq.rb + - node_modules/**/* + # - opal/**/* + - opal.gemspec + - pkg/**/* + - spec/**/* + # - stdlib/**/* + - tasks/**/* + - test/**/* + - tmp/**/* + - vendored-minitest/**/* + - vendor/**/* # present in travis + # Files thate were copied from MRI as is + - 'stdlib/benchmark.rb' + - 'stdlib/observer.rb' + - 'stdlib/open-uri.rb' + - 'stdlib/stringio.rb' + - 'stdlib/source_map/*.rb' + - 'stdlib/racc/parser.rb' + - 'stdlib/e2mmap.rb' + - 'stdlib/matrix.rb' + - 'stdlib/matrix/*.rb' + - 'stdlib/pp.rb' + - 'stdlib/prettyprint.rb' + - 'stdlib/optparse.rb' + - 'stdlib/optparse/*.rb' + - 'stdlib/tmpdir.rb' + - 'stdlib/tempfile.rb' + +inherit_mode: + merge: + - Exclude + +Naming/MethodName: + Exclude: + # Ruby has methods like Integer/Float/Array + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Layout/ClosingParenthesisIndentation: + Enabled: false + +Layout/CommentIndentation: + # The following files use comments to show generated ruby code + Exclude: + - 'lib/opal/rewriters/binary_operator_assignment.rb' + - 'lib/opal/rewriters/logical_operator_assignment.rb' + - 'lib/opal/source_map/file.rb' + +# We need to support older rubies +Layout/IndentHeredoc: + Enabled: false + +Style/FrozenStringLiteralComment: + Exclude: + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Layout/EmptyLineAfterMagicComment: + Exclude: + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Style/GlobalVars: + Exclude: + - 'opal/corelib/kernel.rb' + - 'stdlib/nodejs/irb.rb' + - 'stdlib/console.rb' + - 'stdlib/native.rb' + - 'stdlib/await.rb' + +Layout/ExtraSpacing: + Exclude: + # This files uses extra spaces to show an inheritance tree of error classes + - 'opal/corelib/error.rb' + +Layout/IndentArray: + EnforcedStyle: consistent + +Layout/SpaceAroundOperators: + Exclude: + - 'opal/corelib/error.rb' + +Lint/BooleanSymbol: + Exclude: + # There are AST nodes and rewriters with types :true and :false + - 'lib/opal/nodes/**/*.rb' + - 'lib/opal/rewriters/**/*.rb' + +Lint/InheritException: + Exclude: + - 'lib/opal/builder.rb' + - 'lib/opal/errors.rb' + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Lint/LiteralAsCondition: + Exclude: + # Opal supports if `...js...` + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Lint/Loop: + Exclude: + # This is for optimization purposes mostly + - 'opal/corelib/io.rb' + +# Allow the use of if/unless inside blocks +Style/Next: + Enabled: false + +Lint/RescueException: + Exclude: + # That's what MRI does + - 'opal/corelib/enumerator.rb' + # Promises must care about all exceptions + - 'stdlib/promise.rb' + - 'opal/corelib/binding.rb' + +Lint/StringConversionInInterpolation: + Exclude: + # That's what MRI does + - 'opal/corelib/error.rb' + +Lint/UnusedBlockArgument: + Exclude: + # Variable from Ruby can be accessed in JS, rubocop can't catch it (but JSHint can) + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Lint/UnusedMethodArgument: + Exclude: + # Variable from Ruby can be accessed in JS, rubocop can't catch it (but JSHint can) + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Lint/UselessAssignment: + Exclude: + # Variable from Ruby can be accessed in JS, rubocop can't catch it (but JSHint can) + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Metrics/AbcSize: + Enabled: false + +Metrics/BlockLength: + Enabled: false + +Metrics/BlockNesting: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/ModuleLength: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Metrics/ParameterLists: + Exclude: + # Some Ruby methods take 10 arguments + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Naming/BinaryOperatorParameterName: + Exclude: + # Opal follows MRI argument namings + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Naming/PredicateName: + # Ruby has "has_key?" method + NamePrefixBlacklist: is_, have_ + +Performance/FlatMap: + Exclude: + # That's actually a definition of Enumerable#flat_map + - 'opal/corelib/enumerable.rb' + +Performance/RegexpMatch: + # This cop converts =~ to match? + # But this method was introduced only in 2.4 + Enabled: false + +Performance/UnfreezeString: + Enabled: false + +Style/AsciiComments: + Enabled: false + +Style/CaseEquality: + Exclude: + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + - 'lib/opal/config.rb' + +Style/ClassAndModuleChildren: + Enabled: false + +Style/ClassVars: + Exclude: + # These classes use class variables on purpose + - 'lib/opal/rewriters/binary_operator_assignment.rb' + - 'lib/opal/rewriters/logical_operator_assignment.rb' + +Style/CommandLiteral: + # This cop converts `` to %x{} + Enabled: false + +Style/Documentation: + Enabled: false + +Style/EmptyMethod: + # There are a lot of empty methods that are required to make MSpec working + Exclude: + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Style/IfUnlessModifier: + Enabled: false + +Style/InfiniteLoop: + # while true is faster than loop + Enabled: false + +Style/InverseMethods: + # That's what MRI does + Exclude: + - 'opal/corelib/basic_object.rb' + - 'opal/corelib/kernel.rb' + +Style/MethodMissingSuper: + # Base Opal classes simply can't or shouldn't call super for #method_missing + Exclude: + - 'opal/corelib/basic_object.rb' + - 'opal/corelib/kernel.rb' + - 'opal/corelib/string/inheritance.rb' + - 'stdlib/native.rb' + - 'stdlib/delegate.rb' + - 'stdlib/ostruct.rb' + +Style/MissingRespondToMissing: + Enabled: true + +Style/NumericPredicate: + Enabled: false + +Style/ParallelAssignment: + Enabled: false + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + default: '{}' + Exclude: + # Opal has a convention of %x{} + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Style/SafeNavigation: + # Opal supports old versions of Ruby that don't have safe navigator + Enabled: false + +Style/SpecialGlobalVars: + Enabled: false + +Style/StderrPuts: + Enabled: false + +Style/YodaCondition: + Exclude: + # In Opal there are lot of cases like + # if `..js..` == object + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Layout/MultilineAssignmentLayout: + EnforcedStyle: same_line + +Style/TrailingCommaInArguments: + # Any style is allowed + Enabled: false + +Layout/AlignParameters: + EnforcedStyle: with_fixed_indentation + +Layout/MultilineMethodCallBraceLayout: + EnforcedStyle: new_line + +Style/Lambda: + EnforcedStyle: literal + +Layout/EmptyLines: + # Empty lines can be used to separate interface and implementation + Enabled: false + +Style/EmptyElse: + # Empty 'else' can be used to indicate a potential empty branch condition + EnforcedStyle: nil + +Lint/EmptyWhen: + # Empty 'when' can be used to indicate a potential empty branch condition + Enabled: false + +Style/StringLiterals: + Exclude: + # Nodes are more like DSL, so they are allowed to have any internal rules + # that make the code more readable + - 'lib/opal/nodes/**/*.rb' + +Style/TrailingUnderscoreVariable: + # We treat a, = *b construction as a potential source of bugs + Enabled: false + +Style/WhileUntilModifier: + Enabled: false + +Style/RegexpLiteral: + # Use the style that you like more, but if there are slashes or backslashe + # prefer %r{} syntax. + # Rubocop doesn't check for backslashes, so this rule is disabled. + Enabled: false + +Naming/FileName: + Exclude: + - 'stdlib/opal-builder.rb' + - 'stdlib/nodejs/open-uri.rb' + - 'stdlib/opal-parser.rb' + - 'stdlib/opal-platform.rb' + - 'stdlib/opal-source-maps.rb' + - 'stdlib/opal-replutils.rb' + +Naming/ConstantName: + Exclude: + # MRI has a constant BigDecimal::SIGN_NaN + - 'stdlib/bigdecimal.rb' + +Security/Eval: + Exclude: + # That's what parser does + - 'stdlib/opal-parser.rb' + +Naming/AccessorMethodName: + Exclude: + # StringScanner has method 'get_byte' + - 'stdlib/strscan.rb' + # Exception has method 'set_backtrace' + - 'opal/corelib/error.rb' + +Style/RescueStandardError: + Enabled: false + +Style/TrailingCommaInArrayLiteral: + # Any style is allowed + Enabled: false + +Style/TrailingCommaInHashLiteral: + # Any style is allowed + Enabled: false + +Naming/UncommunicativeMethodParamName: + Exclude: + # This file uses parser's code that doesn't match our styling requirements + - 'lib/opal/parser/patch.rb' + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Lint/BigDecimalNew: + Exclude: + # That's the implementation of the Kernel#BigDecimal + - 'stdlib/bigdecimal/kernel.rb' + +Style/MutableConstant: + Exclude: + - 'opal/**/*.rb' + - 'stdlib/**/*.rb' + +Style/EmptyCaseCondition: + Enabled: false + + +# Use whatever suites the situation, sometimes assign_inside_condition is +# more readable over assign_to_condition despite the risk of repeating the +# variable name. +Style/ConditionalAssignment: + Enabled: false + +Naming/MemoizedInstanceVariableName: + Exclude: + - lib/opal/parser/patch.rb # it's a monkey-patch on the parser gem + - lib/opal/nodes/rescue.rb # we know what we are doing here and no, it's not memoization + +Style/AccessModifierDeclarations: + Enabled: false + +Style/MultipleComparison: + Enabled: false + +Layout/EmptyLineAfterGuardClause: + Enabled: false + +Layout/AlignHash: + Enabled: false + +# No way to set multiple preferred names +Naming/RescuedExceptionsVariableName: + Enabled: false + +Style/Semicolon: + AllowAsExpressionSeparator: true + +Layout/EmptyLinesAroundExceptionHandlingKeywords: + Enabled: false diff --git a/.rubocop/todo.yml b/.rubocop/todo.yml new file mode 100644 index 00000000..c81988a9 --- /dev/null +++ b/.rubocop/todo.yml @@ -0,0 +1,43 @@ +# All items in this file require fixing + +Metrics/LineLength: + Enabled: false + +Lint/AssignmentInCondition: + Exclude: + - 'lib/opal/ast/node.rb' + - 'lib/opal/compiler.rb' + - 'lib/opal/nodes/helpers.rb' + - 'lib/opal/nodes/logic.rb' + - 'lib/opal/nodes/masgn.rb' + - 'lib/opal/nodes/runtime_helpers.rb' + - 'lib/opal/nodes/scope.rb' + - 'lib/opal/nodes/top.rb' + - 'lib/tilt/opal.rb' + - 'opal/corelib/comparable.rb' + - 'opal/corelib/complex.rb' + - 'opal/corelib/marshal/write_buffer.rb' + +Style/GuardClause: + Enabled: false + +Style/ModuleFunction: + Exclude: + - 'lib/opal/config.rb' + - 'lib/opal/util.rb' + - 'stdlib/nodejs/fileutils.rb' + - 'stdlib/js.rb' + +Style/MutableConstant: + Exclude: + - 'lib/opal/nodes/call.rb' + - 'lib/opal/util.rb' + +Lint/HandleExceptions: + Exclude: + - 'stdlib/ostruct.rb' + +Lint/ToJSON: + Exclude: + - 'lib/opal/source_map/map.rb' + - 'stdlib/json.rb' diff --git a/.yardopts b/.yardopts new file mode 100644 index 00000000..b08a2da4 --- /dev/null +++ b/.yardopts @@ -0,0 +1,8 @@ +lib/opal.rb +lib/opal/**/*.rb +--markup=markdown +--markup-provider=redcarpet +--hide-void-return +- +CHANGELOG.md +docs/compiler_directives.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..1937d5f9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1817 @@ +# Change Log + +All notable changes to this project will be documented in this file. +This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0. + +Changes are grouped as follows: +- **Added** for new features. +- **Changed** for changes in existing functionality. +- **Deprecated** for once-stable features removed in upcoming releases. +- **Removed** for deprecated features removed in this release. +- **Fixed** for any bug fixes. +- **Security** to invite users to upgrade in case of vulnerabilities. + + + + + +## [1.4.1](https://github.com/opal/opal/compare/v1.4.0...v1.4.1) - 2022-01-12 + + +### Changed + +- PromiseV2 is now declared a stable interface! + +### Fixed + +- Args named with JS reserved words weren't always renamed when _zsuper_ was involved ([#2385](https://github.com/opal/opal/pull/2385)) + + + + + + +## [1.4.0](https://github.com/opal/opal/compare/v1.3.2...v1.4.0) - 2021-12-24 + + +### Added + +- Implement `chomp:` option for `String#each_line` and `#lines` ([#2355](https://github.com/opal/opal/pull/2355)) +- Ruby 3.1 support and some older Ruby features we missed ([#2347](https://github.com/opal/opal/pull/2347)) + - Use parser in 3.1 mode to support new language-level features like hashes/kwargs value omission, the pin operator for pattern matching + - `Array#intersect?` + - `String#strip` and `String#lstrip` to also remove NUL bytes + - `Integer.try_convert` + - `public`, `private`, `protected`, `module_function` now return their arguments + - `Class#descendants`, `Class#subclasses` + - (<=1.8) `Kernel#local_variables` + - (<=2.3) Set local variables for regexp named captures (`/(?a)/ =~ 'a'` => `b = 'a'`) + - Remove deprecated `NIL`, `TRUE`, `FALSE` constants + - `String#unpack` and `String#unpack1` to support an `offset:` kwarg + - `MatchData#match`, `MatchData#match_length` + - Enumerable modernization + - `Enumerable#tally` to support an optional hash accumulator + - `Enumerable#each_{cons,slice}` to return self + - `Enumerable#compact` + - `Refinement` becomes its own class now + - `Struct#keyword_init?` + - (pre-3.1) Large Enumerator rework + - Introduce `Enumerator::ArithmeticSequence` + - Introduce `Enumerator::Chain` + - Introduce `Enumerator#+` to create `Enumerator::Chain`s + - `Enumerator#{rewind,peek,peek_values,next,next_values}` + - Improve corelib support for beginless/endless ranges and `ArithmeticSequences` + - `String#[]`, `Array#[]`, `Array#[]=`, `Array#fill`, `Array#values_at` + - `Range#step` and `Numeric#step` return an `ArithmeticSequence` when `Numeric` values are in play + - Introduce `Range#%` + - `Enumerator::Yielder#to_proc` + - Fix #2367 + - (2.7) `UnboundMethod#bind_call` + - (Opal) `{Kernel,BasicObject}#{inspect,p,pp,method_missing}` may work with JS native values now, also they now correctly report cycles + - `Enumerable#sum` uses Kahan's summation algorithm to reduce error with floating point values + - `File.dirname` supports a new `level` argument +- Vendor in `optparse` and `shellwords` ([#2326](https://github.com/opal/opal/pull/2326)) +- Preliminary support for compiling the whole `bin/opal` with Opal ([#2326](https://github.com/opal/opal/pull/2326)) + +### Fixed + +- Fix coertion for `Array#drop` ([#2371](https://github.com/opal/opal/pull/2371)) +- Fix coertion for `File.absolute_path` ([#2372](https://github.com/opal/opal/pull/2372)) +- Fix some `IO#puts` edge cases (no args, empty array, nested array, …) ([#2372](https://github.com/opal/opal/pull/2372)) +- Preserve UNC path prefix on File.join ([#2366](https://github.com/opal/opal/pull/2366)) +- Methods on `Kernel`, `BasicObject`, `Boolean` will never return boxed values anymore ([#2293](https://github.com/opal/opal/pull/2293)) + - `false.tap{}` will now correctly return a JS value of `false`, not `Object(false)` +- opal-parser doesn't break on `<<~END` strings anymore ([#2364](https://github.com/opal/opal/pull/2364)) +- Fix error reporting at the early stage of loading ([#2326](https://github.com/opal/opal/pull/2326)) + +### Changed + +- Various outputted code size optimizations - 19% improvement for minified unmangled AsciiDoctor bundle - see: https://opalrb.com/blog/2021/11/24/optimizing-opal-output-for-size/ ([#2356](https://github.com/opal/opal/pull/2356)) +- Second round of code size optimizations - 3% improvement for AsciiDoctor bundle on top of the first round - 23% total - see: https://github.com/opal/opal/pull/2365/commits ([#2365](https://github.com/opal/opal/pull/2365)) + - The calls to `==`, `!=` and `===` changed their semantics slightly: it's impossible to monkey patch those calls for `String` and `Number`, but on other classes they can now return `nil` and it will be handled correctly + - The calls to `!` changed their semantics slightly: it's impossible to monkey patch this call for `Boolean` or `NilClass`. +- Refactored the structure of the internal `stdlib/nodejs` folder ([#2374](https://github.com/opal/opal/pull/2374)) + - Added `nodejs/base` with just I/O, exit, and ARGV management + - Moved `Process::Status` to corelib + - Fixed requires to be more robust + +### Removed + +- Removed `nodejs/irb` from stdlib as it's been broken for some time ([#2374](https://github.com/opal/opal/pull/2374)) +- Removed `Kernel#node_require` from `nodejs/kernel` as it's been deprecated for a long time ([#2374](https://github.com/opal/opal/pull/2374)) + + + + + + +## [1.3.2](https://github.com/opal/opal/compare/v1.3.1...v1.3.2) - 2021-11-10 + + +### Fixed + +- Update documentation ([#2350](https://github.com/opal/opal/pull/2350)) +- Fix `IO#gets` getting an extra char under some circumstances ([#2349](https://github.com/opal/opal/pull/2349)) +- Raise a `TypeError` instead of `UndefinedMethod` if not a string is passed to `__send__` ([#2346](https://github.com/opal/opal/pull/2346)) +- Do not modify `$~` when calling `String#scan` from internal methods ([#2353](https://github.com/opal/opal/pull/2353)) +- Stop interpreting falsey values as a missing constant in `Module#const_get` ([#2354](https://github.com/opal/opal/pull/2354)) + + + + +## [1.3.1](https://github.com/opal/opal/compare/v1.3.0...v1.3.1) - 2021-11-03 + + +### Fixed + +- Fix REPL if bundler environment isn't set ([#2338](https://github.com/opal/opal/pull/2338)) +- Fix Chrome runner if bundler environment isn't set and make it work on other Unixes ([#2339](https://github.com/opal/opal/pull/2339)) +- `Proc#binding` to return a binding if `Binding` is defined (#2341, #2340) +- `Array#zip` to correctly `yield` (#2342, #1611) +- `String#scan` to correctly `yield` (#2342, #1660) + + + + +## [1.3.0](https://github.com/opal/opal/compare/v1.2.0...v1.3.0) - 2021-10-27 + + +### Added + +- Add support for `retry` ([#2264](https://github.com/opal/opal/pull/2264)) +- Modernize Exceptions ([#2264](https://github.com/opal/opal/pull/2264)) + - Add `#cause`, `#backtrace_locations`, `#full_message` to `Exception` + - Normalize backtraces across platforms + - Add `Thread::Backtrace::Location` + - Output Exception#full_message on uncaught exceptions ([#2269](https://github.com/opal/opal/pull/2269)) +- TracePoint `:class` support ([#2049](https://github.com/opal/opal/pull/2049)) +- Implement the Flip-Flop operators ([#2261](https://github.com/opal/opal/pull/2261)) +- Add `JS[]` to access properties on the global object ([#2259](https://github.com/opal/opal/pull/2259)) +- Add `ENV.fetch` to the Nodejs implementation of `ENV` ([#2259](https://github.com/opal/opal/pull/2259)) +- Opal::Cache, an optional compiler cache (enabled by default) (#2242, #2278, #2329) +- Alias for gvars, alias on main ([#2270](https://github.com/opal/opal/pull/2270)) +- Support for GJS (GNOME's JavaScript runtime) runner ([#2280](https://github.com/opal/opal/pull/2280)) +- Scope variables support for `eval()` ([#2256](https://github.com/opal/opal/pull/2256)) +- Add support for `Kernel#binding` ([#2256](https://github.com/opal/opal/pull/2256)) +- A (mostly) correct support for refinements ([#2256](https://github.com/opal/opal/pull/2256)) +- Add support for ECMAScript modules with an `--esm` CLI option ([#2286](https://github.com/opal/opal/pull/2286)) +- Implement `Regexp#names` and add named captures support ([#2272](https://github.com/opal/opal/pull/2272)) +- REPL improvements: ([#2285](https://github.com/opal/opal/pull/2285)) + - Colored output & history support + - `ls` to show available constants and variable +- Add `Method#===` as an alias to `Method#call`, works the same as `Proc#===` ([#2305](https://github.com/opal/opal/pull/2305)) +- Add `IO#gets` and `IO#read_proc` along with other supporting methods ([#2309](https://github.com/opal/opal/pull/2309)) + - Support `#gets` on most platforms, including browsers (via `prompt`) + - Move the REPL to a `--repl` CLI option of the main executable + - Completely refactor IO, now supporting methods like `#each_line` throughout the entire IO chain + - Add a runner for MiniRacer (as `miniracer`) + - Support Windows on the Chrome runner + - Support Windows on the REPL + - Platforms an IO implementations should either set `IO#read_proc` or overwrite `IO#sysread` +- [experimental] Add support for JavaScript async/await ([#2221](https://github.com/opal/opal/pull/2221)) + - Enable the feature by adding a magic comment: `# await: true` + - The magic comment can be also used to mark specific method patterns to be awaited + (e.g. `# await: *_await, sleep` will make any method ending in `_await` or named `sleep` to be awaited) + - Add `Kernel#__await__` as a bridge to the `await` keyword (inspired by CoffeeScript await support) + - Require `opal/await` to get additional support + - Read more on the newly added documentation page +- Better interoperability between legacy Promise (v1) and native Promise (v2) ([#2221](https://github.com/opal/opal/pull/2221)) + - Add `PromiseV1` as an alias to the original (legacy) Promise class + - Add `#to_v1` and `#to_v2` to both classes + - `Promise#to_n` will convert it to a native Promise (v2) +- Add `Opal::Config.esm` to enable/disable ES modules ([#2316](https://github.com/opal/opal/pull/2316)) + - If Config.esm is enabled, SimpleServer does type="module" + - Add new rack-esm example +- Add a QuickJS (https://bellard.org/quickjs/) runner ([#2331](https://github.com/opal/opal/pull/2331)) +- Add `IO#fileno`, `Method#curry`, `Buffer#to_s`, `Pathname.pwd` ([#2332](https://github.com/opal/opal/pull/2332)) +- Add NodeJS support for `ARGF`, `ENV.{inspect,to_h,to_hash,merge}`, `File.{delete,unlink}`, `Kernel#system`, Kernel#\`, `Process::Status` ([#2332](https://github.com/opal/opal/pull/2332)) +- Introduce `__dir__` support ([#2323](https://github.com/opal/opal/pull/2323)) +- Full autoload support ([#2323](https://github.com/opal/opal/pull/2323)) + - Now compatible with `opal-zeitwerk` and `isomorfeus` + - Allow toplevel autoloads + - Allow dynamic autoloads (e.g. can be hooked to fetch a URL upon autoload with a custom loader) + - Allow overwriting `require` (e.g. like rubygems does) + - Allow autoloading trees with `require_tree "./foo", autoload: true` + - Add Module#autoload? +- Autoload parts of the corelib ([#2323](https://github.com/opal/opal/pull/2323)) + +### Fixed + +- Fixed multiple line `Regexp` literal to not generate invalid syntax as JavaScript ([#1616](https://github.com/opal/opal/pull/1616)) +- Fix `Kernel#{throw,catch}` along with `UncaughtThrowError` ([#2264](https://github.com/opal/opal/pull/2264)) +- Update source-map-support to fix an off-by-one error ([#2264](https://github.com/opal/opal/pull/2264)) +- Source map: lines should start from 1, not 0 ([#2273](https://github.com/opal/opal/pull/2273)) +- Allow for multiple underscored args with the same name in strict mode ([#2292](https://github.com/opal/opal/pull/2292)) +- Show instance variables in `Kernel#inspect` ([#2285](https://github.com/opal/opal/pull/2285)) +- `0.digits` was returning an empty array in strict mode ([#2301](https://github.com/opal/opal/pull/2301)) +- Non Integer numbers were responding to `#digits` ([#2301](https://github.com/opal/opal/pull/2301)) +- Correctly delete hash members when dealing with boxed strings ([#2306](https://github.com/opal/opal/pull/2306)) +- Escape string components in interpolated strings (`dstrs`) correctly ([#2308](https://github.com/opal/opal/pull/2308)) +- Don't try to return the JS `debugger` statement, just return `nil` ([#2307](https://github.com/opal/opal/pull/2307)) +- Retain the `-` while stringifying `-0.0` ([#2304](https://github.com/opal/opal/pull/2304)) +- Fix super support for rest args and re-assignments with implicit arguments ([#2315](https://github.com/opal/opal/pull/2315)) +- Fix calling `Regexp#last_match` when `$~` is nil ([#2328](https://github.com/opal/opal/pull/2328)) +- Windows support for chrome runner ([#2324](https://github.com/opal/opal/pull/2324)) + - Use correct node separator for NODE_PATH on Windows + - Pass dir and emulate exec a bit on Windows + - Use Gem.win_platform?, match supported platform to ruby, simplify run +- NodeJS: Drop the first `--` argument in `ARGV` ([#2332](https://github.com/opal/opal/pull/2332)) +- Fix `Object#require` not pointing to `Kernel#require` ([#2323](https://github.com/opal/opal/pull/2323)) + +### Changed + +- Fast-track bad constant names passed to `Struct.new` ([#2259](https://github.com/opal/opal/pull/2259)) +- Renamed internal `super` related helpers, + `find_super_dispatcher` is now `find_super`, `find_iter_super_dispatcher` is now `find_block_super` ([#2090](https://github.com/opal/opal/pull/2090)) +- The `opal-repl` CLI now requires files to be passed with `--require` (or `-r`) instead of the bare filename ([#2309](https://github.com/opal/opal/pull/2309)) +- `Process` is now a Module, not a Class - just like in MRI ([#2332](https://github.com/opal/opal/pull/2332)) +- `s = StringIO.new("a"); s << "b"; s.string` now returns "b", like MRI, but Opal used to return "ab" ([#2309](https://github.com/opal/opal/pull/2309)) + +### Internal + +- Switch from jshint to ESLint ([#2289](https://github.com/opal/opal/pull/2289)) +- Switch from UglifyJS to Terser ([#2318](https://github.com/opal/opal/pull/2318)) +- [CI] Performance regression check (#2276, #2282) + + + + +## [1.2.0](https://github.com/opal/opal/compare/v1.1.1...v1.2.0) - 2021-07-28 + + +### Added + +- Support for multiple arguments in Hash#{merge, merge!, update} ([#2187](https://github.com/opal/opal/pull/2187)) +- Support for Ruby 3.0 forward arguments: `def a(...) puts(...) end` ([#2153](https://github.com/opal/opal/pull/2153)) +- Support for beginless and endless ranges: `(1..)`, `(..1)` ([#2150](https://github.com/opal/opal/pull/2150)) +- Preliminary support for `**nil` argument - see #2240 to note limitations ([#2152](https://github.com/opal/opal/pull/2152)) +- Support for `Random::Formatters` which add methods `#{hex,base64,urlsafe_base64,uuid,random_float,random_number,alphanumeric}` to `Random` and `SecureRandom` ([#2218](https://github.com/opal/opal/pull/2218)) +- Basic support for ObjectSpace finalizers and ObjectSpace::WeakMap ([#2247](https://github.com/opal/opal/pull/2247)) +- A more robust support for encodings (especially binary strings) ([#2235](https://github.com/opal/opal/pull/2235)) +- Support for `"\x80"` syntax in String literals ([#2235](https://github.com/opal/opal/pull/2235)) +- Added `String#+@`, `String#-@` ([#2235](https://github.com/opal/opal/pull/2235)) +- Support for `begin end while ` ([#2255](https://github.com/opal/opal/pull/2255)) +- Added Hash#except and `Hash#except!` ([#2243](https://github.com/opal/opal/pull/2243)) +- Parser 3.0: Implement pattern matching (as part of this `{Array,Hash,Struct}#{deconstruct,deconstruct_keys} methods were added)` ([#2243](https://github.com/opal/opal/pull/2243)) +- [experimental] Reimplement Promise to make it bridged with JS native Promise, this new implementation can be used by requiring `promise/v2` ([#2220](https://github.com/opal/opal/pull/2220)) + +### Fixed + +- Encoding lookup was working only with uppercase names, not giving any errors for wrong ones (#2181, #2183, #2190) +- Fix `Number#to_i` with huge number ([#2191](https://github.com/opal/opal/pull/2191)) +- Add regexp support to `String#start_with` ([#2198](https://github.com/opal/opal/pull/2198)) +- `String#bytes` now works in strict mode ([#2194](https://github.com/opal/opal/pull/2194)) +- Fix nested module inclusion ([#2053](https://github.com/opal/opal/pull/2053)) +- SecureRandom is now cryptographically secure on most platforms (#2218, #2170) +- Fix performance regression for `Array#unshift` on v8 > 7.1 ([#2116](https://github.com/opal/opal/pull/2116)) +- String subclasses now call `#initialize` with multiple arguments correctly (with a limitation caused by the String immutability issue, that a source string must be the first argument and `#initialize` can't change its value) (#2238, #2185) +- Number#step is moved to Numeric ([#2100](https://github.com/opal/opal/pull/2100)) +- Fix class Class < superclass for invalid superclasses ([#2123](https://github.com/opal/opal/pull/2123)) +- Fix `String#unpack("U*")` on binary strings with latin1 high characters, fix performance regression on that call (#2235, #2189, #2129, #2099, #2094, #2000, #2128) +- Fix `String#to_json` output on some edge cases ([#2235](https://github.com/opal/opal/pull/2235)) +- Rework class variables to support inheritance correctly ([#2251](https://github.com/opal/opal/pull/2251)) +- ISO-8859-1 and US-ASCII encodings are now separated as in MRI ([#2235](https://github.com/opal/opal/pull/2235)) +- `String#b` no longer modifies object strings in-place ([#2235](https://github.com/opal/opal/pull/2235)) +- Parser::Builder::Default.check_lvar_name patch ([#2195](https://github.com/opal/opal/pull/2195)) + +### Changed + +- `String#unpack`, `Array#pack`, `String#chars`, `String#length`, `Number#chr`, and (only partially) `String#+` are now encoding aware ([#2235](https://github.com/opal/opal/pull/2235)) +- `String#inspect` now uses `\x` for binary stirngs ([#2235](https://github.com/opal/opal/pull/2235)) +- `if RUBY_ENGINE == "opal"` and friends are now outputing less JS code (#2159, #1965) +- `Array`: `to_a`, `slice`/`[]`, `uniq`, `*`, `difference`/`-`, `intersection`/`&`, `union`/`|`, flatten now return Array, not a subclass, as Ruby 3.0 does ([#2237](https://github.com/opal/opal/pull/2237)) +- `Array`: `difference`, `intersection`, `union` now accept multiple arguments ([#2237](https://github.com/opal/opal/pull/2237)) + +### Deprecated + +- Stopped testing Opal on Ruby 2.5 since it reached EOL. + +### Removed + +- Removed support for the outdated `c_lexer`, it was optional and didn't work for the last few releases of parser ([#2235](https://github.com/opal/opal/pull/2235)) + + + + +## [1.1.1](https://github.com/opal/opal/compare/v1.1.0...v1.1.1) - 2021-02-23 + + +### Fixed + +- The default runner (nodejs) wasn't starting to a bad require in the improved stack-traces ([#2182](https://github.com/opal/opal/pull/2182)) + + + + +## [1.1.0](https://github.com/opal/opal/compare/v1.0.5...v1.1.0) - 2021-02-19 + + +### Added + +- Basic support for `uplevel:` keyword argument in `Kernel#warn` ([#2006](https://github.com/opal/opal/pull/2006)) +- Added a `#respond_to_missing?` implementation for `BasicObject`, `Delegator`, `OpenStruct`, that's meant for future support in the Opal runtime, which currently ignores it ([#2007](https://github.com/opal/opal/pull/2007)) +- `Opal::Compiler#magic_comments` that allows to access magic-comments format and converts it to a hash ([#2038](https://github.com/opal/opal/pull/2038)) +- Use magic-comments to declare helpers required by the file ([#2038](https://github.com/opal/opal/pull/2038)) +- `Opal.$$` is now a shortcut for `Opal.const_get_relative` ([#2038](https://github.com/opal/opal/pull/2038)) +- `Opal.$$$` is now a shortcut for `Opal.const_get_qualified` ([#2038](https://github.com/opal/opal/pull/2038)) +- Added support for `globalThis` as the generic global object accessor ([#2047](https://github.com/opal/opal/pull/2047)) +- `Opal::Compiler#magic_comments` that allows to access magic-comments format and converts it to a hash +- Use magic-comments to declare helpers required by the file +- `Opal.$$` is now a shortcut for `Opal.const_get_relative` +- `Opal.$$$` is now a shortcut for `Opal.const_get_qualified` +- Source-map support for Node.js in the default runner ([#2045](https://github.com/opal/opal/pull/2045)) +- SecureRandom#hex(n) ([#2050](https://github.com/opal/opal/pull/2050)) +- Added a generic implementation of Kernel#caller and #warn(uplevel:) that works with sourcemaps in Node.js and Chrome ([#2065](https://github.com/opal/opal/pull/2065)) +- Added support for numblocks `-> { _1 + _2 }.call(3, 4) # => 7` ([#2149](https://github.com/opal/opal/pull/2149)) +- Support `` and `` in stacktraces, like MRI we now distinguish internal lines from lib/app lines ([#2154](https://github.com/opal/opal/pull/2154)) +- `Array#difference`, `Array#intersection`, `Array#union` as aliases respectively to `Array#{-,&,|}` ([#2151](https://github.com/opal/opal/pull/2151)) +- Aliases `filter{,!}` to `select{,!}` throughout the corelib classes ([#2151](https://github.com/opal/opal/pull/2151)) +- `Enumerable#filter_map`, `Enumerable#tally` ([#2151](https://github.com/opal/opal/pull/2151)) +- Alias `Kernel#then` for `Kernel#yield_self` ([#2151](https://github.com/opal/opal/pull/2151)) +- Method chaining: `{Proc,Method}#{<<,>>}` ([#2151](https://github.com/opal/opal/pull/2151)) +- Added Integer#to_d ([#2006](https://github.com/opal/opal/pull/2006)) +- Added a compiler option `use_strict` which can also be set by the `use_strict` magic comment ([#1959](https://github.com/opal/opal/pull/1959)) +- Add `--rbrequire (-q)` option to `opal` command line executable ([#2120](https://github.com/opal/opal/pull/2120)) + +### Fixed + +- Array#delete_if ([#2069](https://github.com/opal/opal/pull/2069)) +- Array#keep_if ([#2069](https://github.com/opal/opal/pull/2069)) +- Array#reject! ([#2069](https://github.com/opal/opal/pull/2069)) +- Array#select! ([#2069](https://github.com/opal/opal/pull/2069)) +- Struct#dup ([#1995](https://github.com/opal/opal/pull/1995)) +- Integer#gcdlcm ([#1972](https://github.com/opal/opal/pull/1972)) +- Enumerable#to_h ([#1979](https://github.com/opal/opal/pull/1979)) +- Enumerator#size ([#1980](https://github.com/opal/opal/pull/1980)) +- Enumerable#min ([#1982](https://github.com/opal/opal/pull/1982)) +- Enumerable#min_by ([#1985](https://github.com/opal/opal/pull/1985)) +- Enumerable#max_by ([#1985](https://github.com/opal/opal/pull/1985)) +- Set#intersect? ([#1988](https://github.com/opal/opal/pull/1988)) +- Set#disjoint? ([#1988](https://github.com/opal/opal/pull/1988)) +- Set#keep_if ([#1987](https://github.com/opal/opal/pull/1987)) +- Set#select! ([#1987](https://github.com/opal/opal/pull/1987)) +- Set#reject! ([#1987](https://github.com/opal/opal/pull/1987)) +- String#unicode_normalize ([#2175](https://github.com/opal/opal/pull/2175)) +- Module#alias_method ([#1983](https://github.com/opal/opal/pull/1983)) +- Enumerable#minmax_by ([#1981](https://github.com/opal/opal/pull/1981)) +- Enumerator#each_with_index ([#1990](https://github.com/opal/opal/pull/1990)) +- Range#== ([#1992](https://github.com/opal/opal/pull/1992)) +- Range#each ([#1991](https://github.com/opal/opal/pull/1991)) +- Enumerable#zip ([#1986](https://github.com/opal/opal/pull/1986)) +- String#getbyte ([#2141](https://github.com/opal/opal/pull/2141)) +- Struct#dup not copying `$$data` ([#1995](https://github.com/opal/opal/pull/1995)) +- Fixed usage of semicolon in single-line backticks ([#2004](https://github.com/opal/opal/pull/2004)) +- Module#attr with multiple arguments ([#2003](https://github.com/opal/opal/pull/2003)) +- `PathReader` used to try to read missing files instead of respecting the `missing_require_severity` configuration value ([#2044](https://github.com/opal/opal/pull/2044)) +- Removed some unused variables from the runtime ([#2052](https://github.com/opal/opal/pull/2052)) +- Fixed a typo in the runtime ([#2054](https://github.com/opal/opal/pull/2054)) +- Fix Regexp interpolation, previously interpolating with other regexps was broken ([#2062](https://github.com/opal/opal/pull/2062)) +- Set match on StringScanner#skip and StringScanner#scan_until ([#2061](https://github.com/opal/opal/pull/2061)) +- Fix ruby 2.7 warnings ([#2071](https://github.com/opal/opal/pull/2071)) +- Improve the --help descriptions ([#2146](https://github.com/opal/opal/pull/2146)) +- Remove BasicObject#class ([#2166](https://github.com/opal/opal/pull/2166)) +- Time#strftime %j leading zeros ([#2161](https://github.com/opal/opal/pull/2161)) +- Fix `call { true or next }` producing invalid code ([#2160](https://github.com/opal/opal/pull/2160)) +- `define_method` can now be called on the main object ([#2029](https://github.com/opal/opal/pull/2029)) +- Fix nested for-loops ([#2033](https://github.com/opal/opal/pull/2033)) +- Fix Number#round for Integers ([#2030](https://github.com/opal/opal/pull/2030)) +- Fix parsing Unicode characters from Opal ([#2073](https://github.com/opal/opal/pull/2073)) +- Integer#===: improve Integer recognition ([#2089](https://github.com/opal/opal/pull/2089)) +- Regexp: ensure ignoreCase is never undefined ([#2098](https://github.com/opal/opal/pull/2098)) +- Hash#delete: ensure String keys are converted to values ([#2106](https://github.com/opal/opal/pull/2106)) +- Array#shift: improve performance on v8 >7.1 ([#2115](https://github.com/opal/opal/pull/2115)) +- Array#pop(1): improve performance ([#2130](https://github.com/opal/opal/pull/2130)) +- Object#pretty_inspect ([#2139](https://github.com/opal/opal/pull/2139)) +- Fix conversion from UTF-8 to bytes ([#2138](https://github.com/opal/opal/pull/2138)) +- Restore compatibility with Chrome 38, used by Cordova and many mobile browsers ([#2109](https://github.com/opal/opal/pull/2109)) + +### Changed + +- Updated outdated parser version ([#2013](https://github.com/opal/opal/pull/2013)) +- Nashorn has been deprecated but GraalVM still supports it ([#1997](https://github.com/opal/opal/pull/1997)) +- "opal/mini" now includes "opal/io" ([#2002](https://github.com/opal/opal/pull/2002)) +- Regexps assigned to constants are now frozen ([#2007](https://github.com/opal/opal/pull/2007)) +- `Opal.$$` changed from being the constant cache of Object to being a shortcut for `Opal.const_get_relative` ([#2038](https://github.com/opal/opal/pull/2038)) +- Moved REPL implementation from bin/ to its own lib/ file as `opal/repl.rb` ([#2048](https://github.com/opal/opal/pull/2048)) +- `Encoding.default_external` is now initialized with `__ENCODING__` ([#2072](https://github.com/opal/opal/pull/2072)) +- Keep the MersenneTwister implementation private ([#2108](https://github.com/opal/opal/pull/2108)) +- Change parser to 3.0 ([#2148](https://github.com/opal/opal/pull/2148)) +- Fix forwarding a rescued error to a global var: `rescue => $gvar` ([#2154](https://github.com/opal/opal/pull/2154)) +- Now using Parser v3.0 and targeting Ruby 3.0 ([#2156](https://github.com/opal/opal/pull/2156)) +- `Comparable#clamp` to support a Range argument ([#2151](https://github.com/opal/opal/pull/2151)) +- `#to_h` method to support a block (shortform for `.map(&block).to_h`) ([#2151](https://github.com/opal/opal/pull/2151)) +- BigDecimal is now a subclass of Numeric ([#2006](https://github.com/opal/opal/pull/2006)) +- PP to be rebased on upstream Ruby version ([#2083](https://github.com/opal/opal/pull/2083)) +- String to report UTF-8 encoding by default, as MRI does ([#2117](https://github.com/opal/opal/pull/2117)) +- Don't output "Failed to load WithCLexer, using pure Ruby lexer" warning unless in $DEBUG mode ([#2174](https://github.com/opal/opal/pull/2174)) + +### Deprecated + +- Requiring nodejs/stacktrace has been deprecated, source-maps are already + supported by the default Node.js runner or by requiring https://github.com/evanw/node-source-map-support + before loading code compiled by Opal ([#2045](https://github.com/opal/opal/pull/2045)) + +### Removed + +- Removed special compilation for the `Opal.truthy?` and `Opal.falsy?` helpers ([#2076](https://github.com/opal/opal/pull/2076)) +- Removed the deprecated `tainting` compiler config option ([#2072](https://github.com/opal/opal/pull/2072)) + + + + +## [1.0.5](https://github.com/opal/opal/compare/v1.0.4...v1.0.5) - 2020-12-23 + + +### Fixed + +- [Backported] Add --rbrequire (-q) option to opal cmdline tool ([#2120](https://github.com/opal/opal/pull/2120)) +- Improve the --help descriptions ([#2146](https://github.com/opal/opal/pull/2146)) + + + + +## [1.0.4](https://github.com/opal/opal/compare/v1.0.3...v1.0.4) - 2020-12-13 + + +### Fixed + +- [Backported] Using the `--map` / `-P` CLI option was only working in conjunction with other options ([#1974](https://github.com/opal/opal/pull/1974)) + + + + +## [1.0.3](https://github.com/opal/opal/compare/v1.0.2...v1.0.3) - 2020-02-01 + + +### Fixed + +- Fixed compiling code with Unicode chars from Opal with opal-parser ([#2074](https://github.com/opal/opal/pull/2074)) + + + + +## [1.0.2](https://github.com/opal/opal/compare/v1.0.1...v1.0.2) - 2019-12-15 + + +- Increase the timeout for starting Chrome within the Chrome runner ([#2037](https://github.com/opal/opal/pull/2037)) +- Run the Opal code within the body inside Chrome runner, it fixes an issue in opal-rspec ([#2037](https://github.com/opal/opal/pull/2037)) + + + + +## [1.0.1](https://github.com/opal/opal/compare/v1.0.0...v1.0.1) - 2019-12-08 + + +### Changed + +- Relaxed parser version requirement ([#2013](https://github.com/opal/opal/pull/2013)) + + + + +## [1.0.0](https://github.com/opal/opal/compare/v0.11.4...v1.0.0) - 2019-05-12 + + +### Added + +- Added `Module#prepend` and completely overhauled the module and class inheritance system ([#1826](https://github.com/opal/opal/pull/1826)) +- Methods and properties are now assigned with `Object.defineProperty()` as non-enumerable ([#1821](https://github.com/opal/opal/pull/1821)) +- Backtrace now includes the location inside the source file for syntax errors ([#1814](https://github.com/opal/opal/pull/1814)) +- Added support for a faster C-implemented lexer, it's enough to add `gem 'c_lexer` to the `Gemfile` ([#1806](https://github.com/opal/opal/pull/1806)) +- Added `Date#to_n` that returns the JavaScript Date object (in native.rb). (#1779, #1792) +- Added `Array#pack` (supports only `C, S, L, Q, c, s, l, q, A, a` formats). ([#1723](https://github.com/opal/opal/pull/1723)) +- Added `String#unpack` (supports only `C, S, L, Q, S>, L>, Q>, c, s, l, q, n, N, v, V, U, w, A, a, Z, B, b, H, h, u, M, m` formats). ([#1723](https://github.com/opal/opal/pull/1723)) +- Added `File#symlink?` for Node.js. ([#1725](https://github.com/opal/opal/pull/1725)) +- Added `Dir#glob` for Node.js (does not support flags). ([#1727](https://github.com/opal/opal/pull/1727)) +- Added support for a static folder in the "server" CLI runner via the `OPAL_CLI_RUNNERS_SERVER_STATIC_FOLDER` env var +- Added the CLI option `--runner-options` that allows passing arbitrary options to the selected runner, currently the only runner making use of them is `server` accepting `port` and `static_folder` +- Added a short helper to navigate constants manually: E.g. `Opal.$$.Regexp.$$.IGNORECASE` (see docs for "Compiled Ruby") +- Added initial support for OpenURI module (using XMLHttpRequest on browser and [xmlhttprequest](https://www.npmjs.com/package/xmlhttprequest) on Node). ([#1735](https://github.com/opal/opal/pull/1735)) +- Added `String#prepend` to the list of unsupported methods (because String are immutable in JavaScript) +- Added methods (most introduced in 2.4/2.5): + * `Array#prepend` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Array#append` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Array#max` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Array#min` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Complex#finite?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Complex#infinite?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Complex#infinite?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Date#to_time` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Date#next_year` ([#1885](https://github.com/opal/opal/pull/1885)) + * `Date#prev_year` ([#1885](https://github.com/opal/opal/pull/1885)) + * `Hash#slice` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Hash#transform_keys` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Hash#transform_keys!` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Numeric#finite?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Numeric#infinite?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Numeric#infinite?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer#allbits?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer#anybits?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer#digits` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer#nobits?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer#pow` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer#remainder` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Integer.sqrt` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Random.urandom` ([#1757](https://github.com/opal/opal/pull/1757)) + * `String#delete_prefix` ([#1757](https://github.com/opal/opal/pull/1757)) + * `String#delete_suffix` ([#1757](https://github.com/opal/opal/pull/1757)) + * `String#casecmp?` ([#1757](https://github.com/opal/opal/pull/1757)) + * `Kernel#yield_self` ([#1757](https://github.com/opal/opal/pull/1757)) + * `String#unpack1` ([#1757](https://github.com/opal/opal/pull/1757)) + * `String#to_r` ([#1842](https://github.com/opal/opal/pull/1842)) + * `String#to_c` ([#1842](https://github.com/opal/opal/pull/1842)) + * `String#match?` ([#1842](https://github.com/opal/opal/pull/1842)) + * `String#unicode_normalize` returns self ([#1842](https://github.com/opal/opal/pull/1842)) + * `String#unicode_normalized?` returns true ([#1842](https://github.com/opal/opal/pull/1842)) + * `String#[]=` throws `NotImplementedError`([#1836](https://github.com/opal/opal/pull/1836)) + +- Added support of the `pattern` argument for `Enumerable#all?`, `Enumerable#any?`, `Enumerable#none?`. ([#1757](https://github.com/opal/opal/pull/1757)) +- Added `ndigits` option support to `Number#floor`, `Number#ceil`, `Number#truncate`. ([#1757](https://github.com/opal/opal/pull/1757)) +- Added `key` and `receiver` attributes to the `KeyError`. ([#1757](https://github.com/opal/opal/pull/1757)) +- Extended `Struct.new` to support `keyword_init` option. ([#1757](https://github.com/opal/opal/pull/1757)) +- Added a new `Opal::Config.missing_require_severity` option and relative `--missing-require` CLI flag. This option will command how the builder will behave when a required file is missing. Previously the behavior was undefined and partly controlled by `dynamic_require_severity`. Not to be confused with the runtime config option `Opal.config.missing_require_severity;` which controls the runtime behavior. +- Added `Matrix` (along with the internal MRI utility `E2MM`) +- Use shorter helpers for constant lookups, `$$` for relative (nesting) lookups and `$$$` for absolute (qualified) lookups +- Add support for the Mersenne Twister random generator, the same used by CRuby/MRI (#657 & #1891) +- [Nodejs] Added support for binary data in `OpenURI` (#1911, #1920) +- [Nodejs] Added support for binary data in `File#read` (#1919, #1921) +- [Nodejs] Added support for `File#readlines` ([#1882](https://github.com/opal/opal/pull/1882)) +- [Nodejs] Added support for `ENV#[]`, `ENV#[]=`, `ENV#key?`, `ENV#has_key?`, `ENV#include?`, `ENV#member?`, `ENV#empty?`, `ENV#keys`, `ENV#delete` and `ENV#to_s` ([#1928](https://github.com/opal/opal/pull/1928)) + + +### Changed + +- **BREAKING** The dot (`.`) character is no longer replaced with [\s\S] in a multiline regexp passed to Regexp#match and Regexp#match? (#1796, #1795) + * You're advised to always use [\s\S] instead of . in a multiline regexp, which is portable between Ruby and JavaScript +- **BREAKING** `Kernel#format` (and `sprintf` alias) are now in a dedicated module `corelib/kernel/format` and available exclusively in `opal` ([#1930](https://github.com/opal/opal/pull/1930)) + * Previously the methods were part of the `corelib/kernel` module and available in both `opal` and `opal/mini` +- Filename extensions are no longer stripped from filenames internally, resulting in better error reporting ([#1804](https://github.com/opal/opal/pull/1804)) +- The internal API for CLI runners has changed, now it's just a callable object +- The `--map` CLI option now works only in conjunction with `--compile` (or `--runner compiler`) +- The `node` CLI runner now adds its `NODE_PATH` entry instead of replacing the ENV var altogether +- Added `--disable-web-security` option flag to the Chrome headless runner to be able to do `XMLHttpRequest` +- Migrated parser to 2.5. Bump RUBY_VERSION to 2.5.0. +- Exceptions raised during the compilation now add to the backtrace the current location of the opal file if available ([#1814](https://github.com/opal/opal/pull/1814)). +- Better use of `displayName` on functions and methods and more readable temp variable names ([#1910](https://github.com/opal/opal/pull/1910)) +- Source-maps are now inlined and already contain sources, incredibly more stable and precise ([#1856](https://github.com/opal/opal/pull/1856)) + + +### Deprecated + +- The CLI `--server-port 1234` option is now deprecated in favor of using `--runner-options='{"port": 1234}'` +- Including `::Native` is now deprecated because it generates conflicts with core classes in constant lookups (both `Native::Object` and `Native::Array` exist). Instead `Native::Werapper` should be used. +- Using `node_require 'my_module'` to access the native `require()` function in Node.js is deprecated in favor of \`require('my_module')\` because static builders need to parse the call in order to function ([#1886](https://github.com/opal/opal/pull/1886)). + + +### Removed + +- The `node` CLI runner no longer supports passing extra node options via the `NODE_OPT` env var, instead Node.js natively supports the `NODE_OPTIONS` env var. +- The gem "hike" is no longer an external dependency and is now an internal dependency available as `Opal::Hike` ([#1881](https://github.com/opal/opal/pull/1881)) +- Removed the internal Opal class `Marshal::BinaryString` ([#1914](https://github.com/opal/opal/pull/1914)) +- Removed Racc, as it's now replaced by the parser gem ([#1880](https://github.com/opal/opal/pull/1880)) + + + +### Fixed + +- Fix handling of trailing semicolons and JavaScript returns inside x-strings, the behavior is now well defined and covered by proper specs ([#1776](https://github.com/opal/opal/pull/1776)) +- Fixed singleton method definition to return method name. ([#1757](https://github.com/opal/opal/pull/1757)) +- Allow passing number of months to `Date#next_month` and `Date#prev_month`. ([#1757](https://github.com/opal/opal/pull/1757)) +- Fixed `pattern` argument handling for `Enumerable#grep` and `Enumerable#grep_v`. ([#1757](https://github.com/opal/opal/pull/1757)) +- Raise `ArgumentError` instead of `TypeError` from `Numeric#step` when step is not a number. ([#1757](https://github.com/opal/opal/pull/1757)) +- At run-time `LoadError` wasn't being raised even with `Opal.config.missing_require_severity;` set to `'error'`. +- Fixed `Kernel#public_methods` to return instance methods if the argument is set to false. ([#1848](https://github.com/opal/opal/pull/1848)) +- Fixed an issue in `String#gsub` that made it start an infinite loop when used recursively. ([#1879](https://github.com/opal/opal/pull/1879)) +- `Kernel#exit` was using status 0 when a number or a generic object was provided, now accepts numbers and tries to convert objects with `#to_int` (#1898, #1808). +- Fixed metaclass inheritance in subclasses of Module ([#1901](https://github.com/opal/opal/pull/1901)) +- `Method#to_proc` now correctly sets parameters and arity on the resulting Proc ([#1903](https://github.com/opal/opal/pull/1903)) +- Fixed bridged classes having their prototype removed from the original chain by separating them from the Ruby class ([#1909](https://github.com/opal/opal/pull/1909)) +- Improve `String#to_proc` performance ([#1888](https://github.com/opal/opal/pull/1888)) +- Fixed/updated the examples ([#1887](https://github.com/opal/opal/pull/1887)) +- `Opal.ancestors()` now returns false for when provided with JS-falsy objects ([#1839](https://github.com/opal/opal/pull/1839)) +- When subclassing now the constant is set before calling `::inherited` ([#1838](https://github.com/opal/opal/pull/1838)) +- `String#to_sym` now returns the string literal ([#1835](https://github.com/opal/opal/pull/1835)) +- `String#center` now correctly checks length ([#1833](https://github.com/opal/opal/pull/1833)) +- `redo` inside `while` now works properly ([#1820](https://github.com/opal/opal/pull/1820)) +- Fixed compilation of empty/whitespace-only x-strings ([#1811](https://github.com/opal/opal/pull/1811)) +- Fix `||=` assignments on constants when the constant is not yet defined ([#1935](https://github.com/opal/opal/pull/1935)) +- Fix `String#chomp` to return an empty String when `arg == self` ([#1936](https://github.com/opal/opal/pull/1936)) +- Fix methods of `Comparable` when `<=>` does not return Numeric ([#1945](https://github.com/opal/opal/pull/1945)) +- Fix `Class#native_alias` error message ([#1946](https://github.com/opal/opal/pull/1946)) +- Fix `gmt_offset` (alias `utc_offset`) should return 0 if the date is UTC ([#1941](https://github.com/opal/opal/pull/1941)) +- `exceptionDetails.stackTrace` can be undefined ([#1955](https://github.com/opal/opal/pull/1955)) +- Implement `String#each_codepoint` and `String#codepoints` (#1944, #1947) +- [internal] Terminate statement with semi-colon and remove unecessary semi-colon ([#1948](https://github.com/opal/opal/pull/1948)) +- Some steps toward "strict mode" ([#1953](https://github.com/opal/opal/pull/1953)) +- Preserve `Exception.stack`, in some cases the backtrace was lost ([#1963](https://github.com/opal/opal/pull/1963)) +- Make `String#ascii_only?` a little less wrong ([#1951](https://github.com/opal/opal/pull/1951)) +- Minor fixes to `::Native` ([#1957](https://github.com/opal/opal/pull/1957)) + + + + +## [0.11.4](https://github.com/opal/opal/compare/v0.11.3...v0.11.4) - 2018-11-07 + + +### Fixed + +- `Kernel#exit` was using status 0 when a number or a generic object was provided, now accepts numbers and tries to convert objects with `#to_int`. + + + + +## [0.11.3](https://github.com/opal/opal/compare/v0.11.2...v0.11.3) - 2018-08-28 + + +### Fixed + +- Fixed `Array#dup` when `method_missing` support was disabled + + + + +## [0.11.2](https://github.com/opal/opal/compare/v0.11.1...v0.11.2) - 2018-08-24 + + +### Fixed + +- Remove symlink that caused problems on Windows + + + + +## [0.11.1](https://github.com/opal/opal/compare/v0.11.0...v0.11.1) - 2018-07-17 + + +### Added + +- Added support for a static folder in the "server" CLI runner via the `OPAL_CLI_RUNNERS_SERVER_STATIC_FOLDER` env var +- Added ability to pass the port to the "server" CLI runner using the `OPAL_CLI_RUNNERS_SERVER_PORT` (explicit option passed via CLI is still working but deprecated) +- Added a new `Opal::Config.missing_require_severity` option and relative `--missing-require` CLI flag. This option will command how the builder will behave when a required file is missing. Previously the behavior was undefined and partly controlled by `dynamic_require_severity`. Not to be confused with the runtime config option `Opal.config.missing_require_severity;` which controls the runtime behavior. +- At run-time `LoadError` wasn't being raised even with `Opal.config.missing_require_severity;` set to `'error'`. + + + + +## [0.11.0](https://github.com/opal/opal/compare/v0.10.6...v0.11.0) - 2017-12-08 + + +### Added + +- Added support for complex (`0b1110i`) and rational (`0b1111r`) number literals. ([#1487](https://github.com/opal/opal/pull/1487)) +- Added 2.3.0 methods: + * `Array#bsearch_index` + * `Array#dig` + * `Enumerable#chunk_while` + * `Enumerable#grep_v` + * `Enumerable#slice_after` + * `Enumerable#slice_when` + * `Hash#>` + * `Hash#<` + * `Hash#>=` + * `Hash#>=` + * `Hash#dig` + * `Hash#fetch_values` + * `Hash#to_proc` + * `Struct#dig` + * `Kernel#itself` +- Added safe navigator (`&.`) support. ([#1532](https://github.com/opal/opal/pull/1532)) +- Added Random class with seed support. The following methods were reworked to use it: + * `Kernel.rand` + * `Kernel.srand` + * `Array#shuffle` + * `Array#shuffle!` + * `Array#sample` +- Added rudimental history support to `opal-repl`, just create the history file (`~/.opal-repl-history`) and it record the last 1000 lines +- Added `JS::Error` error class that can be used to catch any JS error. +- Added `Method#source_location` and `Method#comments`. +- Added a deprecation API that can be set to raise on deprecation with: `Opal.raise_on_deprecation = true` +- Added `Opal::SimpleServer` as the quickest way to get up and running with Opal: `rackup -ropal -ropal/simple_server -b 'Opal.append_path("app"); run Opal::SimpleServer.new'` +- Added `String#ascii_only?` ([#1592](https://github.com/opal/opal/pull/1592)) +- Added `StringScanner#matched_size` ([#1595](https://github.com/opal/opal/pull/1595)) +- Added `Hash#compare_by_identity` ([#1657](https://github.com/opal/opal/pull/1657)) + + +### Removed + +- Dropped support for IE8 and below, and restricted Safari and Opera support to the last two versions +- Dropped support for PhantomJS as it was [abandoned](https://groups.google.com/forum/#!topic/phantomjs/9aI5d-LDuNE). + + +### Changed + +- Removed self-written lexer/parser. Now uses parser/ast gems to convert source code to AST. ([#1465](https://github.com/opal/opal/pull/1465)) +- Migrated parser to 2.3. Bump RUBY_VERSION to 2.3.0. +- Changed to be 2.3 compliant: + * `Enumerable#chunk` (to take only a a block) + * `Enumerable#slice_before` (to raise proper argument errors) + * `Number#positive?` (to return false for 0) +- Use meaningful names for temporary variables in compiled JavaScript (e.g. for `def foo` was `TMP_123`, now `TMP_foo_123`) +- Dynamic require severity now defaults to `:ignore` meaning that by default a `LoadError` will be raised at runtime instead of compile time. + + +### Deprecated + +- `require 'opal/server` and `Opal::Server` are deprecated in favor of `require 'opal/sprockets/server'` and `Opal::Sprockets::Server` (now part of the opal-sprockets gem). + + +### Removed + +- Removed `yaml` from stdlib, the older implementation was only available for NodeJS and not tested. Replace with `require 'nodejs/yaml'` +- Extracted sprockets support to `opal-sprockets` which should allow for wider support and less coupling (e.g. the `opal` gem will now be able to improve the compiler without worrying about `sprockets` updates). All the old behavior is preserved except for `Opal::Server` that has become `Opal::Sprockets::Server` (see Deprecated section above). + + +### Changed + +- Strip Regexp flags that are unsupported by browsers (backport), previously they were ignored, lately most of them now raise an error for unknown flags. + + +### Fixed + +- Newly compliant with the Ruby Spec Suite: + * `Module#class_variables` + * `Module#class_variable_get` + * `Module#class_variable_set` + * `Module#remove_class_variable` + * `Module#include?` + * `Numeric#step` ([#1512](https://github.com/opal/opal/pull/1512)) + +- Improvements for Range class ([#1486](https://github.com/opal/opal/pull/1486)) + * Moved private/tainted/untrusted specs to not supported + * Conforming `Range#to_s` and `Range#inspect` + * Starting `Range#bsearch` implementation + * Simple `Range#step` implementation + * Fixing `Range#min` for empty Ranges + * Fixing `Range#last(n)` `Range#first(n)` and one edge case of `Range#each` + * Fixing some `Range#step` issues on String ranges + * Simple `Range#bsearch` implementation, passes about half the specs + * Minor styling improvements. Fixed size of `Range#step`. + * Compile complex ranges to "Range.new" so there will be a check for begin and end to be comparable. + +- Fixed `defined?` for methods raising exceptions +- Fixed `Kernel#loop` (to catch `StopIteration` error) +- Fixed inheritance from the `Module` class. +- Fixed using `--preload` along with `--no-opal` for CLI +- Fixed `Integer("0")` raising `ArgumentError` instead of parsing as 0 +- Fixed `JSON#parse` to raise `JSON::ParserError` for invalid input +- `Module#append_features` now detects cyclic includes +- `Process.clock_gettime(Process::CLOCK_MONOTONIC)` will now return true monotonic values or raise `Errno::EINVAL` if no monotonic clock is available +- Opal::Builder no longer always raises an error when a dependency isn't found and instead respects `dynamic_require_severity` value +- Fixed a constant reference to `Sprockets::FileNotFound` that previously pointed to `Opal::Sprockets` instead of `::Sprockets`. + + + + +## [0.10.6](https://github.com/opal/opal/compare/v0.10.5...v0.10.6) - 2018-06-21 + + +### Changed + +- Strip Regexp flags that are unsupported by browsers (backport), previously they were ignored, lately most of them now raise an error for unknown flags. + + +### Fixed + +- Fixed a constant reference to `Sprockets::FileNotFound` that previously pointed to `Opal::Sprockets` instead of `::Sprockets`. + + + + +## [0.10.5](https://github.com/opal/opal/compare/v0.10.4...v0.10.5) - 2017-06-21 + + +### Fixed + +- Fix `Time#zone` for zones expressed numerically + + + + +## [0.10.4](https://github.com/opal/opal/compare/v0.10.3...v0.10.4) - 2017-05-06 + + +### Changed + +- Better `Opal::Config` options documentation and organization +- Always cache source-maps at build-time so they're available once enabled + + + + +## [0.10.3](https://github.com/opal/opal/compare/v0.10.2...v0.10.3) - 2016-10-31 + + +### Fixed + +- Fixed inheritance from the `Module` class ([#1476](https://github.com/opal/opal/pull/1476)) +- Fixed source map server with url-encoded paths +- Silence Sprockets 3.7 deprecations, full support for Sprockets 4 will be available in Opal 0.11 +- Don't print the full stack trace with deprecation messages + + + + +## [0.10.2](https://github.com/opal/opal/compare/v0.10.1...v0.10.2) - 2016-09-09 + + +### Changed + +- Avoid special utf-8 chars in method names, now they start with `$$` + + + + +## [0.10.1](https://github.com/opal/opal/compare/v0.10.0...v0.10.1) - 2016-07-06 + + +### Fixed + +- Fixed `-L` option for compiling requires as modules ([#1510](https://github.com/opal/opal/pull/1510)) + + + + +## [0.10.0](https://github.com/opal/opal/compare/v0.9.4...v0.10.0) - 2016-07-04 + + +### Added + +- Pathname#relative_path_from +- Source maps now include method names +- `Module#included_modules` works +- Internal runtime cleanup ([#1241](https://github.com/opal/opal/pull/1241)) +- Make it easier to add custom runners for the CLI ([#1261](https://github.com/opal/opal/pull/1261)) +- Add Rack v2 compatibility ([#1260](https://github.com/opal/opal/pull/1260)) +- Newly compliant with the Ruby Spec Suite: + * `Array#slice!` + * `Array#repeated_combination` + * `Array#repeated_permutation` + * `Array#sort_by!` + * `Enumerable#sort` + * `Enumerable#max` + * `Enumerable#each_entry` ([#1303](https://github.com/opal/opal/pull/1303)) + * `Module#const_set` + * `Module#module_eval` with a string +- Add `-L` / `--library` option to compile only the code of the library ([#1281](https://github.com/opal/opal/pull/1281)) +- Implement `Kernel.open` method ([#1218](https://github.com/opal/opal/pull/1218)) +- Generate meaningful names for functions representing Ruby methods +- Implement `Pathname#join` and `Pathname#+` methods ([#1301](https://github.com/opal/opal/pull/1301)) +- Added support for `begin;rescue;else;end`. +- Implement `File.extname` method ([#1219](https://github.com/opal/opal/pull/1219)) +- Added support for keyword arguments as lambda parameters. +- Super works with define_method blocks +- Added support for kwsplats. +- Added support for squiggly heredoc. +- Implement `Method#parameters` and `Proc#parameters`. +- Implement `File.new("path").mtime`, `File.mtime("path")`, `File.stat("path").mtime`. +- if-conditions now support `null` and `undefined` as falsy values ([#867](https://github.com/opal/opal/pull/867)) +- Implement IO.read method for Node.js ([#1332](https://github.com/opal/opal/pull/1332)) +- Implement IO.each_line method for Node.js ([#1221](https://github.com/opal/opal/pull/1221)) +- Generate `opal-builder.js` to ease the compilation of Ruby library from JavaScript ([#1290](https://github.com/opal/opal/pull/1290)) + + +### Changed + +- Remove deprecation of `Opal::Environment` after popular request +- Setting `Opal::Config.dynamic_require_severity` will no longer affect `Opal.dynamic_require_severity` which now needs to be explicitly set if it differs from the default value of `"warning"` (See also the `Opal.dynamic_require_severity` rename below). +- The new default for `Opal::Config.dynamic_require_severity` is now `:warning` +- `Opal.dynamic_require_severity` and `OPAL_CONFIG` are now merged into `Opal.config.missing_require_severity` (defaults to `error`, the expected ruby behavior) and `Opal.config.unsupported_features_severity` (defaults to `warning`, e.g. a one-time heads up that freezing isn't supported). Added variable `__OPAL_COMPILER_CONFIG__` that contains compiler options that may be used in runtime. +- `Hash` instances should now list the string map (`$$smap`) as the first key, making debugging easier (most hashes will just have keys there). +- Handle Pathname object in Pathname constructor + + +### Deprecated + +- `Opal::Processor.stubbed_files` and `Opal::Processor.stub_file` in favor of `Opal::Config.stubbed_files` + + +### Removed + +- Removed the previously deprecated `Opal::Fragment#to_code` +- Removed the previously deprecated `Opal::Processor.load_asset_code` +- Removed the previously deprecated acceptance of a boolean as single argument to `Opal::Server.new` + + +### Fixed + +- `Module#ancestors` and shared code like `====` and `is_a?` deal with singleton class modules better ([#1449](https://github.com/opal/opal/pull/1449)) +- `Class#to_s` now shows correct names for singleton classes +- `Pathname#absolute?` and `Pathname#relative?` now work properly +- `File::dirname` and `File::basename` are now Rubyspec compliant +- `SourceMap::VLQ` patch ([#1075](https://github.com/opal/opal/pull/1075)) +- `Regexp::new` no longer throws error when the expression ends in \\\\ +- `super` works properly with overwritten alias methods ([#1384](https://github.com/opal/opal/pull/1384)) +- `NoMethodError` does not need a name to be instantiated +- `method_added` fix for singleton class cases +- Super now works properly with blocks ([#1237](https://github.com/opal/opal/pull/1237)) +- Fix using more than two `rescue` in sequence ([#1269](https://github.com/opal/opal/pull/1269)) +- Fixed inheritance for `Array` subclasses. +- Always populate all stub_subscribers with all method stubs, as a side effect of this now `method_missing` on bridged classes now works reliably ([#1273](https://github.com/opal/opal/pull/1273)) +- Fix `Hash#instance_variables` to not return `#default` and `#default_proc` ([#1258](https://github.com/opal/opal/pull/1258)) +- Fix `Module#name` when constant was created using `Opal.cdecl` (constant declare) like `ChildClass = Class.new(BaseClass)` ([#1259](https://github.com/opal/opal/pull/1259)) +- Fix issue with JavaScript `nil` return paths being treated as true ([#1274](https://github.com/opal/opal/pull/1274)) +- Fix `Array#to_n`, `Hash#to_n`, `Struct#to_n` when the object contains native objects (#1249, #1256) +- `break` semantics are now correct, except for the case in which a lambda containing a `break` is passed to a `yield` ([#1250](https://github.com/opal/opal/pull/1250)) +- Avoid double "/" when `Opal::Sprockets.javascript_include_tag` receives a prefix with a trailing slash. +- Fixed context of evaluation for `Kernel#eval` and `BasicObject#instance_eval` +- Fix `Module#===` to use all ancestors of the passed object ([#1284](https://github.com/opal/opal/pull/1284)) +- Fix `Struct.new` to be almost compatible with Rubyspec ([#1251](https://github.com/opal/opal/pull/1251)) +- Fix `Enumerator#with_index` to return the result of the previously called method. +- Improved `Date.parse` to cover most date formatting cases. +- Fixed `Module#const_get` for dynamically created constants. +- Fixed `File.dirname` to return joined String instead of Array. +- Fixed multiple assignment for constants, i.e., allowing `A, B = 1, 2`. +- Fixed `Number#[]` with negative number. Now `(-1)[1]` returns 1. +- Fixed parsing of pre-defined `$-?` global variables. +- Fixed parsing of unicode constants. +- Fixed parsing of quoted heredoc identifier. +- Fixed parsing of mass assignment of method call without parentheses. +- Fixed parsing of `%I{}` lists. +- Fixed parsing of `%{}` lists when list item contains same brackets. +- Fixed an issue with `"-"` inside the second arg of `String#tr` +- Fixed Base64 and enabled specs +- Fixed method definition in method body. +- Partially implemented `Marshal.load`/`Marshal.dump`. In order to use it require `opal/full`. +- Fixed docs for Compiled Ruby - Native section. Rename opal variable to win since window was causing error +- Fixed the `--map` option, now correclty outputs the sourcemap as json + + +### Removed + +- Remove support for configuring Opal via `Opal::Processor`, the correct place is `Opal::Config` +- Remove `Opal.process` which used to be an alias to `Sprockets::Environment#[]` + + + + +## [0.9.4](https://github.com/opal/opal/compare/v0.9.3...v0.9.4) - 2016-06-20 + + +### Fixed + +- Rebuilt the gem with Rubygems 2.4.8 as building with 2.5.1+ would make the gem un-installable + +- Removed all symlinks from `node_module` directories to avoid further issues building the gem + + + + +## [0.9.3](https://github.com/opal/opal/compare/v0.9.2...v0.9.3) - 2016-06-16 + + +### Fixed + +- `Hash#initialize` now accepts JS `null` as well as `undefined`, restoring its 0.8 behavior + + + + +## [0.9.2](https://github.com/opal/opal/compare/v0.9.1...v0.9.2) - 2016-01-09 + + +### Fixed + +- Rebuilt the gem with Ruby 2.2 as building with 2.3 would make the gem un-installable + + + + +## [0.9.1](https://github.com/opal/opal/compare/v0.9.0...v0.9.1) - 2016-01-09 + + +### Fixed + +- Backport rack2 compatibility ([#1260](https://github.com/opal/opal/pull/1260)) +- Fixed issue with JS nil return paths being treated as true ([#1274](https://github.com/opal/opal/pull/1274)) +- Fix using more than two `rescue` in sequence ([#1269](https://github.com/opal/opal/pull/1269)) + + + + +## [0.9.0](https://github.com/opal/opal/compare/v0.8.1...v0.9.0) - 2015-12-20 + + +### Added + +- A `console` wrapper has been added to the stdlib, requiring it will make available the `$console` global variable. +- `method_added`, `method_removed` and `method_undefined` reflection now works. +- `singleton_method_added`, `singleton_method_removed` and `singleton_method_undefined` reflection now works. +- Now you can bridge a native class to a Ruby class that inherits from another Ruby class +- `Numeric` semantics are now compliant with Ruby. +- `Complex` has been fully implemented. +- `Rational` has been fully implemented. +- `Kernel#raise` now properly re-raises exceptions (regardless of how many levels deep you are) and works properly if supplied a class that has an exception method. +- `Exception#exception`, `Exception::exception`, `Exception#message`, and `Exception#to_s` are fully implemented +- You can make direct JavaScript method calls on using the `recv.JS.method`syntax. Has support for method calls, final callback (as a block), property getter and setter (via `#[]` and `#[]=`), splats, JavaScript keywords (via the `::JS` module) and global functions (after `require "js"`). +- `Set#superset?`, `Set#subset?`, and the respective `proper_` variant of each are now implemented +- `NameError` and `NoMethodError` - add `#name` and `#args` attributes +- `RegExp#match` now works correctly in multiline mode with white space +- `BasicObject#instance_eval` now can accept a string argument (after `require "opal-parser"`) +- Adds Nashorn (Java 8+ Javascript engine) runner `bundle exec bin/opal -R nashorn -r nashorn hello.rb` + +- Newly compliant with the Ruby Spec Suite: + * `Enumerable#chunk` + * `Enumerable#each_cons` + * `Enumerable#minmax` + * `Range#to_a` ([#1246](https://github.com/opal/opal/pull/1246)) + * `Module` comparison methods: `#<` `#<=` `#<=>` `#>` `#>=` + - `OpenStruct#method_missing` + - `OpenStruct#inspect` + - `OpenStruct#to_s` + - `OpenStruct#delete_field` + + +### Changed + +- Renamed: + - `Hash.keys` => `Hash.$$keys` + - `Hash.map` => `Hash.$$map` + - `Hash.smap` => `Hash.$$smap` +- `Kernel#pp` no longer forwards arguments directly to `console.log`, this behavior has been replaced by stdlib's own `console.rb` (see above). +- `Opal::Sprockets.javascript_include_tag` has been added to allow easy debug mode (i.e. with source maps) when including a sprockets asset into an HTML page. + + +### Deprecated + +- `Opal::Processor.load_asset_code(sprockets, name)` has been deprecated in favor of `Opal::Sprockets.load_asset(name, sprockets)`. + + +### Fixed + +- Fixed usage of JavaScript keywords as instance variable names for: + - `Kernel#instance_variable_set` + - `Kernel#instance_variable_get` + - `Kernel#instance_variables` +- `Struct#hash` now works properly based on struct contents +- No longer crashes when calling a method with an opt arg followed by an optional kwarg when called without the kwarg +- Operator methods (e.g. `+`, `<`, etc.) can be handled by `method_missing` +- Fix issue where passing a block after a parameter and a hash was causing block to not be passed (e.g. `method1 some_param, 'a' => 1, &block`) +- Method defs issued inside `Module#instance_eval` and `Class#instance_eval`, and the respective `exec` now create class methods +- Now with enabled arity checks calling a method with more arguments than those supported by its signature raises an `ArgumentError` as well. +- Previously arity checks would raise an error without clearing the block for a method, that could lead to strange bugs in case the error was rescued. +- `Regexp#===` returns false when the right hand side of the expression cannot be coereced to a string (instead of throwing a `TypeError`) +- `Regexp#options` has been optimized and correctly returns 0 when called on a Regexp literal without any options (e.g. `//`) +- Fix `Kernel#exit` to allow exit inside `#at_exit` +- Fixed a number of syntax errors (e.g. #1224 #1225 #1227 #1231 #1233 #1226) +- Fixed `Native()` when used with `Array` instances containing native objects (which weren't wrapped properly) – #1212 +- Fix `Array#to_n`, `Hash#to_n`, `Struct#to_n` when the object contains native objects ([#1249](https://github.com/opal/opal/pull/1249)) +- Internal cleanup and lots of bugs! + + + + +## [0.8.1](https://github.com/opal/opal/compare/v0.8.0...v0.8.1) - 2015-10-12 + + +### Removed + +- Use official Sprockets processor cache keys API: + The old cache key hack has been removed. + Add `Opal::Processor.cache_key` and `Opal::Processor.reset_cache_key!` to + reset it as it’s cached but should change whenever `Opal::Config` changes. + +### Fixed + +- Fix an issue for which a Pathname was passed instead of a String to Sprockets. + + + + +## [0.8.0](https://github.com/opal/opal/compare/v0.7.2...v0.8.0) - 2015-07-16 + + +### Added + +- `Hash[]` implementation fully compliant with rubyspec + +- Newly compliant with the Ruby Spec Suite: + - `Array#bsearch` + - `Array#combination` + - `Array#permutation` + - `Array#product` + - `Array#rotate!` + - `Array#rotate` + - `Array#sample` + - `Array#to_h` + - `Array#values_at` + - `Array#zip` + - `Enumerator#with_index` + - `Kernel#===` + - `Kernel#Array` + - `Kernel#Float` + - `Kernel#Hash` + - `Kernel#Integer` + - `Kernel#String` + - `Kernel#format` + - `Kernel#sprintf` + - `MatchData#==` + - `MatchData#eql?` + - `MatchData#values_at` + - `Module#instance_methods` + - `Regexp#match` + - `String#%` + - `String#===` + - `String#==` + - `String#[]` + - `String#each_line` + - `String#eql?` + - `String#index` + - `String#inspect` + - `String#lines` + - `String#match` + - `String#next` + - `String#oct` + - `String#scan` + - `String#slice` + - `String#split` + - `String#succ` + - `String#to_i` + - `String#try_convert` + + +### Changed + +- Updated to Sprockets v3.0. +- Enable operator inlining by default in the compiler. + + +### Removed + +- Removed `minitest` from stdlib. It's not part of MRI and it never belonged there, checkout the `opal-minitest` gem instead. + + +### Fixed + +- Delegate dependency management directly to Sprockets (when used) making sourcemaps swift again. + This means code generated by sprockets will always need to be bootstrapped via `Opal.load` or `Opal.require`. + Luckily `Opal::Processor.load_asset_code(sprockets, name)` does just that in the right way. +- Fix `Promise#always`. +- Fix `String#split` when no match is found and a limit is provided +- Fix `require_tree(".")` when used from file at the root of the assets paths +- Parser: Allow trailing comma in paren arglists, after normal args as well as assoc args. +- Parser: Fix parsing of parens following divide operator without a space. +- Parser: Fix bug where keyword arguments could not be parsed if method definition did not have parens around arguments. +- `Module#const_get` now accepts a scoped constant name +- `Regexp#===` sets global match data vars + + + + +## [0.7.2](https://github.com/opal/opal/compare/v0.7.1...v0.7.2) - 2015-04-23 + + +- Remove Sprockets 3.0 support (focus moved to upcoming 0.8) +- Fix version number consistency. + + + + +## [0.7.1](https://github.com/opal/opal/compare/v0.7.0...v0.7.1) - 2015-02-13 + + +- CLI options `-d` and `-v` now set respectively `$DEBUG` and `$VERBOSE` +- Fixed a bug that would make the `-v` CLI option wait for STDIN input +- Add the `-E` / `--no-exit` CLI option to skip implicit `Kernel#exit` call +- Now the CLI implicitly calls `Kernel#exit` at the end of the script, thus making `at_exit` blocks be respected. + + + + +## [0.7.0](https://github.com/opal/opal/compare/v0.6.3...v0.7.0) - 2015-02-01 + + +- Stop keyword-arg variable names leaking to global javascript scope + +- `Class#native_class` now also exposes `MyClass.new` (Ruby) as `Opal.global.MyClass.new()` (JS) + +- Add CRuby (MRI) tests harness to start checking Opal against them too. + +- Add Minitest to the stdlib. + +- Add `Date#<=>` with specs. + +- Show extended info and context upon parsing, compiling and building errors. + +- Support keyword arguments in method calls and definitions. + +- Fix `begin`/`rescue` blocks to evaluate to last expression. + +- Add support for `RUBY_ENGINE/RUBY_PLATFORM != "opal"` pre-processor directives. + + if RUBY_ENGINE != "opal" + # this code never compiles + end + +- Fix donating methods defined in modules. This ensures that if a class includes more than one module, then the methods defined on the class respect the order in which the modules are included. + +- Improved support for recursive `Hash` for both `#inspect` and `#hash`. + +- Optimized `Hash` implementation for `String` and `Symbol`, they have a separate hash-table in which they're used as both keys and hashes. + +- Added real `#hash` / `eql?` support, previously was relying on `.toString()`. + +- `String#to_proc` now uses `__send__` instead of `send` for calling + methods on receivers. + +- Deprecated `Opal::Sprockets::Environment`. It can easily be replaced by `Opal::Server` or by appending `Opal.paths` to a `Sprockets::Environment`: + + Sprockets::Environment.new.tap { |e| Opal.paths.each {|p| e.append_path(p)} } + +- Add `Set` methods `#classify`, `#collect!`, `#map!`, `#subtract` `#replace`, + `#difference` and `#eql?` + +- Support `module_function` without args to toggle module functions. + +- Fix bug where command calls with no space and sym arg were incorrectly parsed. + +- Add some `StringScanner` methods. + +- Add `Date#<<` and `Date#>>` implementations. + +- Support nested directories using `require_tree` directive. + +- Fix bug where Exception subclasses could not have methods defined on them. + +- Fix symbols with interpolations `:"#{foo}"` + +- Implement $1..N matchers and rewrite support for $~, $', $& and $\`. + +- Implement `Regexp.last_match`. + +- Fixed `-@` unary op. precedence with a numeric and followed by a method call (e.g. `-1.foo` was parsed as `-(1.foo)`) + +- `require_relative` (with strings) is now preprocessed, expanded and added to `Compiler#requires` + +- Rewritten the require system to respect requires position (previously all the requires were stacked up at the top of the file) + +- Implement for-loop syntax + +- Add Array#| + +- Fix Range.new to raise `ArgumentError` on contructor values that cannot + be compared + +- Fix compiler bug where Contiguous strings were not getting concatenated. + +- Cleanup generated code for constant access. All constant lookups now go through `$scope.get('CONST_NAME')` to produce cleaner code and a unified place for const missing dispatch. + +- Remove `const_missing` option from compiler. All constant lookups are now strict. + +- Add initial support for Module#autoload. + +- Fix `Enumerator#with_index`, `Numeric#round`. + + + + +## [0.6.3](https://github.com/opal/opal/compare/v0.6.2...v0.6.3) - 2014-11-23 + + +- Fix `Regexp.escape` internal regexp + + + + +## [0.6.2](https://github.com/opal/opal/compare/v0.6.1...v0.6.2) - 2014-04-24 + + +- Added Range#size + +- `opal` executable now reads STDIN when no file or `-e` are passed + +- `opal` executable doesn't exit after showing version on `-v` if other options are passed + +- (Internal) improved the mspec runner + + + + +## [0.6.1](https://github.com/opal/opal/compare/v0.6.0...v0.6.1) - 2014-04-14 + + +- Updated RubySpec to master and added `rubysl-*` specs. Thanks to Mike Owens (@mieko) + +- Added `Kernel#require_remote(url)` in `opal-parser` that requires files with basic synchronous ajax + GET requests. It is used to load ``. + +- Various parsing fixes (Hash parsing, `def` returns method name, cleanup `core/util`, Enumerator fixes) + +- Added `#native_reader`, `#native_writer` and `#native_accessor`as class methods + donated by `include Native` + +- Added specs for Sprockets' processors (both .js.rb and .opalerb), backported from `opal-rails` + +- Set 2.1.1 as RUBY_VERSION + +- Add `opal-build` command utility to easily build libraries to js + +- Add `opal-repl` to gemspec executables, + previously was only available by using Opal from source + +- Fix parsing `=>` in hash literals where it would sometimes incorrectly + parse as a key name. + + + + +## [0.6.0](https://github.com/opal/opal/compare/v0.5.5...v0.6.0) - 2014-03-05 + + +- Fix parsing of escapes in single-strings ('foo\n'). Only ' and \ + characters now get escaped in single quoted strings. Also, more escape + sequences in double-quoted strings are now supported: `\a`, `\v`, `\f`, + `\e`, `\s`, octal (`\314`), hex (`\xff`) and unicode (`\u1234`). + +- Sourcemaps revamp. Lexer now tracks column and line info for every token to + produce much more accurate sourcemaps. All method calls are now located on + the correct source line, and multi-line xstrings are now split to generate + a map line-to-line for long inline javascript parts. + +- Merged sprockets support from `opal-sprockets` directly into Opal. For the + next release, the exernal `opal-sprockets` gem is no longer needed. This + commit adds `Opal::Processor`, `Opal::Server` and `Opal::Environment`. + +- Introduce pre-processed if directives to hide code from Opal. Two special + constant checks now take place in the compiler. Either `RUBY_ENGINE` or + `RUBY_PLATFORM` when `== "opal"`. Both if and unless statements can pick + up these logic checks: + + if RUBY_ENGINE == "opal" + # this code compiles + else + # this code never compiles + end + + Unless: + + unless RUBY_ENGINE == "opal" + # this code never compiles + end + + This is particularly useful for avoiding `require()` statements being + picked up, which are included at compile time. + +- Add special `debugger` method to compiler. Compiles down to javascript + `debugger` keyword to start in-browser debug console. + +- Add missing string escapes to `read_escape` in lexer. Now most ruby escape + sequences are properly detected and handled in string parsing. + +- Disable escapes inside x-strings. This means no more double escaping all + characters in x-strings and backticks. (`\n` => `\n`). + +- Add `time.rb` to stdlib and moved `Time.parse()` and `Time.iso8601()` + methods there. + +- `!` is now treated as an unary method call on the object. Opal now parsed + `!` as a def method name, and implements the method on `BasicObject`, + `NilClass` and `Boolean`. + +- Fixed bug where true/false as object literals from javascript were not + correctly being detected as truthy/falsy respectively. This is due to the + javascript "feature" where `new Boolean(false) !== false`. + +- Moved `native.rb` to stdlib. Native support must now be explicitly required + into Opal. `Native` is also now a module, instead of a top level class. + Also added `Native::Object#respond_to?`. + +- Remove all core `#as_json()` methods from `json.rb`. Added them externally + to `opal-activesupport`. + +- `Kernel#respond_to?` now calls `#respond_to_missing?` for compliance. + +- Fix various `String` methods and add relevant rubyspecs for them. `#chars`, + `#to_f`, `#clone`, `#split`. + +- Fix `Array` method compliance: `#first`, `#fetch`, `#insert`, `#delete_at`, + `#last`, `#splice`, `.try_convert`. + +- Fix compliance of `Kernel#extend` and ensure it calls `#extended()` hook. + +- Fix bug where sometimes the wrong regexp flags would be generated in the + output javascript. + +- Support parsing `__END__` constructs in ruby code, inside the lexer. The + content is gathered up by use of the parser. The special constant `DATA` + is then available inside the ruby code to read the content. + +- Support single character strings (using ? prefix) with escaped characters. + +- Fix lexer to detect dereferencing on local variables even when whitespace + is present (`a = 0; a [0]` parses as a deference on a). + +- Fix various `Struct` methods. Fixed `#each` and `#each_pair` to return + self. Add `Struct.[]` as synonym for `Struct.new`. + +- Implemented some `Enumerable` methods: `#collect_concat`, `#flat_map`, + `#reject`, `#reverse_each`, `#partition` and `#zip`. + +- Support any Tilt template for `index_path` in `Opal::Server`. All index + files are now run through `Tilt` (now supports haml etc). + +- Fix code generation of `op_asgn_1` calls (`foo[val] += 10`). + +- Add `base64` to stdlib. + +- Add promises implementation to stdlib. + +- Add `Math` module to corelib. + +- Use `//#` instead of `//@` deprecated syntax for sourceMappingURL. + +- Implicitly require `erb` from stdlib when including erb templates. + +- Fix `Regexp.escape` to also escape '(' character. + +- Support '<' and '>' as matching pairs in string boundrys `%q`. + +- `Opal::Server` no longer searches for an index file if not specified. + +- Move `Math` and `Encoding` to stdlib. Can be required using + `require 'math'`, etc. + +- Fix some stdlib `Date` methods. + +- Fix `Regexp.escape` to properly escape \n, \t, \r, \f characters. + +- Add `Regexp.quote` as an alias of `escape`. + + + + +## [0.5.5](https://github.com/opal/opal/compare/v0.5.4...v0.5.5) - 2013-11-25 + + +- Fix regression: add `%i[foo bar]` style words back to lexer + +- Move corelib from `opal/core` to `opal/corelib`. This stops files in `core/` clashing with user files. + + + + +## [0.5.4](https://github.com/opal/opal/compare/v0.5.3...v0.5.4) - 2013-11-20 + + +- Reverted `RUBY_VERSION` to `1.9.3`. Opal `0.6.0` will be the first release for `2.0.0`. + + + + +## [0.5.3](https://github.com/opal/opal/compare/v0.5.2...v0.5.3) - 2013-11-20 + + +- Opal now targets ruby 2.0.0 + +- Named function inside class body now generates with `$` prefix, e.g. `$MyClass`. This makes it easier to wrap/bridge native functions. + +- Support Array subclasses + +- Various fixes to `String`, `Kernel` and other core classes + +- Fix `Method#call` to use correct receiver + +- Fix `Module#define_method` to call `#to_proc` on explicit argument + +- Fix `super()` dispatches on class methods + +- Support `yield()` calls from inside a block (inside a method) + +- Cleanup string parsing inside lexer + +- Cleanup parser/lexer to use `t` and `k` prefixes for all tokens + + + + +## [0.5.2](https://github.com/opal/opal/compare/v0.5.1...v0.5.2) - 2013-11-11 + + +- Include native into corelib for 0.5.x + + + + +## [0.5.1](https://github.com/opal/opal/compare/v0.5.0...v0.5.1) - 2013-11-10 + + +- Move all corelib under `core/` directory to prevent filename clashes with `require` + +- Move `native.rb` into stdlib - must now be explicitly required + +- Implement `BasicObject#__id__` + +- Cleanup and fix various `Enumerable` methods + + + + +## [0.5.0](https://github.com/opal/opal/compare/v0.4.4...v0.5.0) - 2013-11-03 + + +- Optimized_operators is no longer a compiler option +- Replace `Opal.bridge_class()` with class Foo < \`bar\` syntax +- Expose `Opal.bridge_class()` for bridging native prototypes +- Source maps improvements +- Massive Rubyspec cleanup + passing specs +- Massive Corelib/Stdlib cleanup + fixes +- Massive internal cleanup + fixes + +*See the [full diff](https://github.com/opal/opal/compare/v0.4.4...v0.5.0) for more details (almost 800 commits)* + + + + +## [0.4.4](https://github.com/opal/opal/compare/v0.4.3...v0.4.4) - 2013-08-13 + + +- Remove native object method calls +- Add Struct class +- Add method stubs as method_missing option, stubs enabled by default +- Native is now used to wrap native objects directly +- Fix Hash.new and Hash.allocate for subclasses +- Generate sourcemaps from fragments +- Allow blocks to be passed to zsuper (no args) calls +- Fix yield when given 1 or multiple arguments for block destructuring + + + + +## [0.4.3](https://github.com/opal/opal/compare/v0.4.2...v0.4.3) - 2013-07-24 + + +- Re-implement class system. Classes are now real objects instead of converted Procs. This allows classes to properly inherit methods from each other. +- Fix exception hierarchy. Not all standard exception classes were subclassing the correct parent classes, this is now fixed. +- Move ERB into stdlib. The erb compiler/parser has also been moved into lib/ +- Opal::Builder class. A simple port/clone of sprockets general building. This allows us to build projects similar to the way opal-sprockets does. +- Move json.rb to stdlib. + + + + +## [0.4.2](https://github.com/opal/opal/compare/v0.4.1...v0.4.2) - 2013-07-03 + + +- Added `Kernel#rand`. (fntzr) + +- Restored the `bin/opal` executable in gemspec. + +- Now `.valueOf()` is used in `#to_n` of Boolean, Numeric, Regexp and String + to return the naked JavaScript value instead of a wrapping object. + +- Parser now wraps or-ops in paranthesis to stop variable order from + leaking out when minified by uglify. We now have code in this + format: `(((tmp = lhs) !== false || !==nil) ? tmp : rhs)`. + + + + +## [0.4.1](https://github.com/opal/opal/compare/v0.4.0...v0.4.1) - 2013-06-16 + + +- Move sprockets logic out to external opal-sprockets gem. That now + handles the compiling and loading of opal files in sprockets. + + + + +## [0.4.0](https://github.com/opal/opal/compare/v0.3.44...v0.4.0) - 2013-06-15 + + +- Added fragments to parser. All parser methods now generate one or + more Fragments which store the original sexp. This allows us to + enumerate over them after parsing to map generated lines back to + original line numbers. + +- Reverted `null` for `nil`. Too buggy at this time. + +- Add Opal::SprocketsParser as Parser subclass for handling parsing + for sprockets environment. This subclass handles require statements + and stores them for sprockets to use. + +- Add :irb option to parser to keep top level lvars stored inside + opal runtime so that an irb session can be persisted and maintain + access to local variables. + +- Add Opal::Environment#use_gem() helper to add a gem to opals load + path. + +- Stop pre-setting ivars to `nil`. This is no longer needed as `nil` + is now `null` or `undefined`. + +- Use `null` as `nil` in opal. This allows us to send methods to + `null` and `undefined`, and both act as `nil`. This makes opal a + much better javascript citizen. **REVERTED** + +- Add Enumerable#none? with specs. + +- Add Opal.block_send() runtime helper for sending methods to an + object which uses a block. + +- Remove \_klass variable for denoting ruby classes, and use + constructor instead. constructor is a javascript property used for + the same purpose, and this makes opal fit in as a better js citizen. + +- Add Class.bridge\_class method to bridge a native constructor into an + opal class which will set it up with all methods from Object, as + well as giving it a scope and name. + +- Added native #[]= and #to_h methods, for setting properties and + converting to a hash respectivaly. + +- Fix bug where '::' was parsed as :colon2 instead of :colon3 when in + an args scope. Fixes #213 + +- Remove lots of properties added to opal classes. This makes normal + js constructors a lot closer to opal classes, making is easier to + treat js classes as opal classes. + +- Merge Hash.from_native into Hash.new + + + + +## [0.3.44](https://github.com/opal/opal/compare/v0.3.43...v0.3.44) - 2013-05-31 + + +- Cleanup runtime, and remove various flags and functions from opal + objects and classes (moving them to runtime methods). + +- Remove some activesupport methods into external lib. + +- Add/fix lots of String methods, with specs. + +- Add more methods to MatchData class. + +- Implement $' and $` variables. + +- Opal can now call methods on all native objects, via method missing + dispatcher. + +- Add Opal::Environment as custom sprockets subclass which adds all + opal load paths automatically. + + + + +## [0.3.43](https://github.com/opal/opal/compare/v0.3.42...v0.3.43) - 2013-05-02 + + +- Stop inlining respond_to? inside the parser. This now fully respects + an object overriding respond_to?. + +- Expose `Opal.eval()` function when parser is loaded for parsing + and running strings of ruby code. + +- Add erb to corelib (as well as compiler to gem lib). ERB files with + .opalerb extension will automatically be compiled into Template + constant. + +- Added some examples into examples/ dir. + +- Add Opal.send() javascript function for sending methods to ruby + objects. + +- Native class for wrapping and interacting with native objects and + function calls. + +- Add local_storage to stdlib as a basic wrapper around localStorage. + +- Make method_missing more performant by reusing same dispatch function + instead of reallocating one for each run. + +- Fix Kernel#format to work in firefox. String.prototype.replace() had + different semantics for empty matching groups which was breaking + Kernel#format. + + + + +## [0.3.42](https://github.com/opal/opal/compare/v0.3.41...v0.3.42) - 2013-03-21 + + +- Fix/add lots of language specs. + +- Seperate sprockets support out to opal-sprockets gem. + +- Support %r[foo] style regexps. + +- Use mspec to run specs on corelib and runtime. Rubyspecs are now + used, where possible to be as compliant as possible. + + + + +## [0.3.41](https://github.com/opal/opal/compare/v0.3.40...v0.3.41) - 2013-02-26 + + +- Remove bin/opal - no longer required for building sources. + +- Depreceate Opal::Environment. The Opal::Server class provides a better + method of using the opal load paths. Opal.paths still stores a list of + load paths for generic sprockets based apps to use. + + + + +## [0.3.40](https://github.com/opal/opal/compare/v0.3.39...v0.3.40) - 2013-02-23 + + +- Add Opal::Server as an easy to configure rack server for testing and + running Opal based apps. + +- Added optional arity check mode for parser. When turned on, every method + will have code which checks the argument arity. Off by default. + +- Exception subclasses now relfect their name in webkit/firefox debuggers + to show both their class name and message. + +- Add Class#const_set. Trying to access undefined constants by a literal + constant will now also raise a NameError. + + + + +## [0.3.39](https://github.com/opal/opal/compare/v0.3.38...v0.3.39) - 2013-02-20 + + +- Fix bug where methods defined on a parent class after subclass was defined + would not given subclass access to method. Subclasses are now also tracked + by superclass, by a private '_inherited' property. + +- Fix bug where classes defined by `Class.new` did not have a constant scope. + +- Move Date out of opal.rb loading, as it is part of stdlib not corelib. + +- Fix for defining methods inside metaclass, or singleton_class scopes. + + + + +## [0.3.38](https://github.com/opal/opal/compare/v0.3.37...v0.3.38) - 2013-02-19 + + +- Add Native module used for wrapping objects to forward calls as native calls. + +- Support method_missing for all objects. Feature can be enabled/disabled on `Opal::Processor`. + +- Hash can now use any ruby object as a key. + +- Move to Sprockets based building via `Opal::Processor`. + + + + +## [0.3.37](https://github.com/opal/opal/compare/v0.3.36...v0.3.37) - 2013-02-15 + + +- Extract the JavaScript runtime to `opal/runtime.js` +- Add core `template.rb` for the basis of template libraries for Opal + + + + +## [0.3.36](https://github.com/opal/opal/compare/v0.3.35...v0.3.36) - 2013-02-08 + + +- Use Ruby `require` directive inside Sprockets +- Depreceate `Opal.process` in favour of `Opal::Environment` + + + + +## [0.3.35](https://github.com/opal/opal/compare/v0.3.34...v0.3.35) - 2013-02-05 + + +- Internal cleanup + + + + +## [0.3.34](https://github.com/opal/opal/compare/v0.3.33...v0.3.34) - 2013-02-05 + + +- Fix bug where camelcased lvars could parse as constants +- Add `Array#shuffle` +- Migrate to Sprockets-based building +- Move ERB to separate gem + + + + +## [0.3.33](https://github.com/opal/opal/compare/000000...v0.3.33) - 2013-01-18 + + +- Implement attr_reader/writer/accessor for dynamic uses +- Hash internals update + + + + diff --git a/CONDUCT.md b/CONDUCT.md new file mode 100644 index 00000000..e7b4d5f0 --- /dev/null +++ b/CONDUCT.md @@ -0,0 +1,13 @@ +This document provides community guidelines for a safe, respectful, productive, +and collaborative place for any person who is willing to contribute to the Opal +community. It applies to all “collaborative space”, which is defined as +community communications channels (such as mailing lists, submitted patches, +commit comments, etc.). + +* Participants will be tolerant of opposing views. +* Participants must ensure that their language and actions are free of personal + attacks and disparaging personal remarks. +* When interpreting the words and actions of others, participants should always + assume good intentions. +* Behaviour which can be reasonably considered harassment will not be + tolerated. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..2f70d721 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +# Contributing and Reporting + +This is the issue tracker for Opal. If you have a more general question about +using Opal (or related libraries) then use the [stackoverflow tag (#opalrb)][SO], or the *Gitter* chatroom at [opal/opal][gitter] +(also available as IRC at `irc.gitter.im`). + +[SO]: http://stackoverflow.com/questions/ask?tags=opalrb +[gitter]: https://gitter.im/opal/opal + +What follows is a quick checklist you can before sending issues or pull-requests, for in-depth instructions on how to hack the internals of Opal and setup the development environment please see [`HACKING.md`][hacking]. + +[hacking]: https://github.com/opal/opal/blob/master/HACKING.md + +## Submitting a New Issue + +1. Before opening a new issue, search for previous discussions including closed + ones. Add comments there if a similar issue is found. + +2. Please report the version on which the issue is found (`opal -v`). + +3. The best issues have steps to reproduce the error. Common ways to do that are: + - A snippet of Ruby code + - A CLI command with its output, e.g. `opal -ve 'p String != Symbol' # => false'` + + +## Submitting a Pull Request + +1. Before sending pull requests make sure all tests run and pass (see `HACKING.md` in this repo). + +2. Make sure to use a similar coding style to the rest of the code base. Some examples follow: + - In Ruby and JavaScript code we use 2 spaces (no tabs) + - In JavaScript we use `snake_case` for methods and variables + +3. Make sure to have updated all the relevant documentation, both for API (using _yardoc_ syntax) and the Guides + +4. Add a Changelog entry at the top of `UNRELEASED.md` + + +### A note on commits in PRs + +You could be asked to squash your commits during a PR review. That doesn't mean there's a preference for a single commit for each PR, rather it's a request to have each commit focused on a specific group changes and avoid the sequence of changes, fixups and reverts that tell an interesting story but in the end make the use of `git blame` quite difficult. + +__That said, these are quite loose requirements in the spirit of keeping contributing enjoyable 🤓__ + + diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..21865fae --- /dev/null +++ b/Gemfile @@ -0,0 +1,50 @@ +source 'https://rubygems.org' +gemspec + +v = -> version { Gem::Version.new(version) if version } + +ruby_version = v[RUBY_VERSION] + +tilt_version = ENV['TILT_VERSION'] +rack_version = ENV['RACK_VERSION'] +sprockets_version = ENV['SPROCKETS_VERSION'] + +gem 'json', '< 1.8.1', platform: :ruby if ruby_version < v['2.2'] +gem 'rack-test', '< 0.8' if ruby_version <= v['2.0'] +gem 'coveralls', platform: :mri + +# Some browsers have problems with WEBrick +gem 'puma' unless RUBY_ENGINE == 'truffleruby' + +gem 'rack', rack_version if rack_version +gem 'tilt', tilt_version if tilt_version +gem 'sprockets', sprockets_version if sprockets_version + +group :repl do + if RUBY_VERSION.to_f >= 2.3 + gem 'mini_racer', platform: :mri, require: false + else + gem 'mini_racer', '< 0.2.0', platform: :mri, require: false + gem 'libv8', '~> 6.3.0', platform: :mri, require: false + end + + gem 'therubyrhino', platform: :jruby, require: false +end + +group :browser do + gem 'selenium-webdriver', '>= 3.0.0.beta3.1', platform: :mri +end + +group :development do + gem 'rb-fsevent' + gem 'guard', require: false + + if RUBY_PLATFORM =~ /darwin/ + gem 'terminal-notifier-guard' + gem 'terminal-notifier' + end +end unless ENV['CI'] + +group :doc do + gem 'redcarpet' unless RUBY_ENGINE == 'truffleruby' +end unless ENV['CI'] diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..82258c15 --- /dev/null +++ b/Guardfile @@ -0,0 +1,76 @@ +require 'guard/plugin' + +class ::Guard::Opal < Plugin + def mspec *paths + command = ['bundle', 'exec', './bin/opal-mspec', *paths.flatten] + result = time(:mspec, *paths) { system *command } + notify 'MSpec', result + end + + def rspec *paths + command = ['bundle', 'exec', 'rspec', *paths.flatten] + result = time(:rspec, *paths) { system *command } + notify 'RSpec', result + end + + def notify lib, result + if result + ::Guard::Notifier.notify( + 'Success ♥︎', title: "#{lib} results", image: :success, priority: 1 + ) + else + ::Guard::Notifier.notify( + 'Failed ♠︎', title: "#{lib} results", image: :failed, priority: 1 + ) + end + end + + def color *args + Guard::UI.send :color, *args + end + + def terminal_columns + cols = `tput cols 2> /dev/tty`.strip.to_i + ($?.success? && cols.nonzero?) ? cols : 80 + end + + def time *titles + columns = terminal_columns + puts color("=== running: #{titles.join(' ')} ".ljust(columns,'='), :cyan) + s = Time.now + result = yield + t = (Time.now - s).to_f + puts color("=== time: #{t} seconds ".ljust(columns, '='), :cyan) + result + end + + def run_on_changes(changes) + m = changes + path = m[0] + puts color("Searching specs for #{m[0]}...", :yellow) + case path + when %r{^spec/lib} then rspec path + when %r{^spec/ruby} then mspec path + when %r{^opal/corelib} + name = File.basename(path, '.rb') + mspec "spec/ruby/core/#{name}/**/*_spec.rb" + when %r{^lib/opal/(.*)\.rb$} + name = $1 + specs = Dir["spec/lib/#{name}_spec.rb"] + rspec *specs + end + end + + def run_all + time(:all) { system 'bundle', 'exec', 'rake' } + end +end + +guard :opal do + ignore %r{^(tmp|tasks|pkg|cdn|build|node_modules|grammar.rb)} + watch %r{^spec/.*} + watch %r{^lib/.*} + watch %r{^bin/.*} + watch %r{^opal/.*} + watch %r{^stdlib/.*} +end diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 00000000..9633ba31 --- /dev/null +++ b/HACKING.md @@ -0,0 +1,191 @@ +# Hacking + +## Quick Start + +[Fork opal/opal on GitHub](https://github.com/opal/opal/fork), then clone the fork to your machine: + +``` +$ git clone git://github.com//opal.git +``` + +Setup the project: + +``` +$ bin/setup +``` + +Run the test suite: + +``` +$ bundle exec rake +``` + +You are now ready to make your first contribution to Opal! At a high level, your workflow will be to: + +1. Make changes to Opal source code +2. Run the test suite to make sure it still passes +3. Submit a pull request + + +## Down The Rabbit Hole + +Before making changes to Opal source, you need to understand a little about how the test suite works. Every spec that Opal test suite executes is listed in `spec/ruby_specs` file. Each line in that file is a path to either a spec file or a directory full of spec files. If it's a path to a directory, all spec files in that directory will be executed when you run the test suite. Lines starting with a `!` represent files that are excluded (i.e. "execute all files in a given directory, *except* this file"), and lines starting with a `#` are ignored as comments. All paths are relative to the top-level `specs` directory. Let's follow one of these paths - `ruby/core/string/sub_spec` - and see where it goes. + +Navigating to `spec/ruby/core` directory, you see that it contains multiple sub-directories, usually named after the Ruby class or module. Drilling further down into `spec/ruby/core/string` you see all the spec files for the various `String` behaviors under test, usually named by a method name followed by `_spec.rb`. Opening `spec/ruby/core/string/sub_spec.rb` you finally see the code that checks the correctness of Opal's implementation of the `String#sub` method's behavior. + +When you execute `$ bundle exec rake`, the code in this file is executed, along with all the other specs in the entire test suite. It's a good idea to run the entire test suite when you feel you reached a certain milestone in the course of making your changes (exactly what that means is up to you), and definitely do `$ bundle exec rake` before committing your changes to make sure they have not introduced regressions or other unintended side effects. + +But you will want to run tests as often as possible, after every small change, and running the entire test suite will slow you down. You need to be able to execute a single spec that is concerned with the feature you are currently working on. To accomplish this, just add `PATTERN` to your spec invocation command, like this: + +``` +$ bundle exec rake mspec_ruby_nodejs PATTERN=spec/ruby/core/string/sub_spec.rb +``` + +This will make sure that only `spec/ruby/core/string/sub_spec.rb` is run, and no other specs are executed. Globs can be used too: + +``` +$ bundle exec rake mspec_ruby_nodejs PATTERN="spec/ruby/core/string/*_spec.rb" +``` + +Another way to quickly validate ideas and play with your changes is to use `opal-repl`, a tool similar to `irb`. Running `opal-repl` drops you into an interactive environment with your current version of Opal loaded, including any changes you have made. + +``` +$ bundle exec opal-repl +>> 2 + 2 +=> 4 +>> +``` + +When quickly iterating on an idea, even `opal-repl` may feel a bit too heavy, because after making a change in Opal, you must `exit` from `opal-repl` and do `$ bundle exec opal-repl` again to load Opal with your latest changes. In this case, you can run `opal` with the `-e` option, which executes a piece of code you pass to it once, then returns to the shell. This means that in order to run it again after making another adjustment to Opal, all you have to do is hit the up arrow key on your keyboard and press the enter key. This is the fastest way to go from making a change in Opal to seeing its effect. + +``` +$ bundle exec opal -e "3.times {puts 'hello'}" +hello +hello +hello +$ +``` + +Let's recap what we covered so far. `spec/ruby_specs` is the "master list" of all the specs that get executed when you do `$ bundle exec rake`. You know where to find individual specs, inspect them, and execute them selectively or in bulk. But how do you know which specs to work on? You may be tempted to compare the contents of one of the directories in `spec/ruby/core` with the list of paths in `spec/ruby_specs`, add the missing paths to the "master list", run `$ bundle exec rake`, and start fixing the failures by implementing the missing features. However, chances are that as you are reading this, there are plenty of failing tests in the specs that are already listed in `spec/ruby_specs`. How can that be if `$ bundle exec rake` runs green? To understand this, you need to get acquainted with the concept of spec filters. + +There are two types of spec filters in the Opal project: `spec/filters/bugs` and `spec/filters/unsupported`. Both filters have the same effect: any spec failures that are noted inside any of the files inside of these directories are ignored when running the spec suite, i.e. they are not reported as failures. Even though their effect is the same, the purpose of `bugs` and `unsupported` filters is different. As the name suggests, `unsupported` filters list _permanent_ failures, things that other Ruby implementations can do that Opal cannot and will never be able to do (by design and by virtue of being implemented on top of JavaScript running in the browser environment). `bugs` filters, on the other hand, are _temporary_ failures, problems that need to be worked on. Problems that Opal needs your help with. Think of the `bugs` directory and the files contained within it as your "TO DO" list for contributing to Opal. + +Comment out any of the `fail` lines in any of the files in the `spec/filters/bugs` directory, run `$bundle exec rake`, and watch it fail. Make it pass and submit a pull request - that's all there is to it :) Happy hacking! + +Core classes use each other and your changes may fix other bugs in `spec/filters/bugs`. If you think it's possible, run an inverted test suite by providing environment variable `INVERT_RUNNING_MODE=true`: + +``` +$ env INVERT_RUNNING_MODE=true RUBYSPECS=true PATTERN="spec/ruby/core/string/*_spec.rb" rake mspec_ruby_nodejs +``` + +This command will execute tests marked as "bugs" from every file in the `spec/ruby/core/string` directory. After running it you will get a list of specs that in fact are passing. Feel free to remove them from `spec/filters/bugs`. + +Note: Opal has some bugs that may cause a shared state between tests. Sometimes green specs are green only in the inverted test suite, so after removing them from `/bugs`, run a regular test suite one more time to verify that everything is fine. + +Also there are some specs in `spec/ruby/language/while_spec.rb` that cause an infinite loop. Make sure to comment them before running a whole inverted test suite. + +## Benchmarking + +There are two ways to benchmark Opal's performance: one way is to write a program (or a set of programs) that takes sufficently long time to execute, then measure the execution time, and the other is to execute a specific Ruby Spec Suite example (or a set of examples) multiple times, then measure the execution time. Let's call the former "Traditional Benchmarking", and the latter "The Ruby Spec Suite Benchmarking". + +Regardless of which of the two types of benchmarking above you happen to be doing, the reporting of benchmark results works the same way: `bundle exec rake bench:report`. + +It's important to understand that benchmarking in Opal works on the principle of a single, shared benchmarking workspace, a *bench*, where the results of each benchmark run that you perform get automatically saved. When you do `bundle exec rake bench:report`, you get a combined report of all of the benchmark results that are currently sitting in your workspace. This means you can check out an older commit, run benchmarks, checkout a newer commit, run benchmarks, then run the report to see the results from the two commits side-by-side. After you're done, (or before starting a new benchmarking session), you can do `bundle exec rake bench:clear` to reset your workspace to a clean slate. + +You can get a list of all the available benchmarking commands by running `bundle exec rake -T | grep bench` as shown below. + +``` +$ bundle exec rake -T | grep bench + +rake bench:clear # Delete all benchmark results +rake bench:opal # Benchmark Opal +rake bench:report # Combined report of all benchmark results +rake bench:ruby # Benchmark Ruby +``` + +### Traditional Benchmarking + +At the root of the opal project tree is a folder called `benchmark` that contains a file called `benchmarks`. This file lists all of the benchmarks that will be run if you do `bundle exec bench:opal` without specifying any particular benchmark file(s) as parameters to this rake task. In the example below, I pick which benchmarks to run by passing their file paths as parameters to the rake task. + +Start with a clean slate: + +``` +$ bundle exec rake bench:clear + +rm tmp/bench/* +``` + +Run two benchmark programs from the MRI benchmarking suite by passing their file paths as parameters: +(Note: passing params to Rake tasks is tricky - notice there is no space after the comma!) + +``` +$ bundle exec rake bench:opal[test/cruby/benchmark/bm_app_answer.rb,test/cruby/benchmark/bm_app_factorial.rb] + +bundle exec opal benchmark/run.rb test/cruby/benchmark/bm_app_answer.rb test/cruby/benchmark/bm_app_factorial.rb | tee tmp/bench/Opal1 +test/cruby/benchmark/bm_app_answer.rb 0.7710001468658447 +test/cruby/benchmark/bm_app_factorial.rb 0.0820000171661377 +=============================================== +Executed 2 benchmarks in 0.8530001640319824 sec +``` + +In this case, I want to see how Opal's results stack up against MRI's results, so I will run the same set of benchmarks for Ruby: + +``` +$ bundle exec rake bench:ruby[test/cruby/benchmark/bm_app_answer.rb,test/cruby/benchmark/bm_app_factorial.rb] + +bundle exec ruby benchmark/run.rb test/cruby/benchmark/bm_app_answer.rb test/cruby/benchmark/bm_app_factorial.rb | tee tmp/bench/Ruby1 +test/cruby/benchmark/bm_app_answer.rb 0.04913724200014258 +test/cruby/benchmark/bm_app_factorial.rb 1.3288652799965348 +=============================================== +Executed 2 benchmarks in 1.3780025219966774 sec +``` + +Now I'm ready to see the result of the two runs side-by-side: + +``` +$ bundle exec rake bench:report + +Benchmark Opal1 Ruby1 +test/cruby/benchmark/bm_app_answer.rb 0.771 0.049 +test/cruby/benchmark/bm_app_factorial.rb 0.082 1.329 +``` + +If I were to continue running benchmarks, more columns would be added to the report. You can select which columns you want to display (and in what order) by passing their names as params to the rake task like so: `bundle exec rake bench:report[Ruby1,Opal1]` + +### The Ruby Spec Suite Benchmarking + +This type of benchmarking relies on a feature of MSpec whereby you can ask it to execute every example in a given spec multiple times. Adding `BM=` to your regular spec suite invocation command will hook into this MSpec functionality, collect timing information, and dump the results into the benchmarking workspace, making them available for reporting. Below is an example run with a single spec and `BM` set to `100`, meaning each example in the spec would be run 100 times. + +``` +$ bundle exec rake mspec_ruby_nodejs PATTERN=spec/ruby/core/array/permutation_spec.rb BM=100 + +... + +Benchmark results have been written to tmp/bench/Spec1 +To view the results, run bundle exec rake bench:report +``` + +Now let's see the report: +(Spec names can be very long, scroll to the right to see the numbers) + +``` +$ bundle exec rake bench:report +Benchmark Spec1 +Array#permutation_returns_an_Enumerator_of_all_permutations_when_called_without_a_block_or_arguments 0.117 +Array#permutation_returns_an_Enumerator_of_permutations_of_given_length_when_called_with_an_argument_but_no_block 0.064 +Array#permutation_yields_all_permutations_to_the_block_then_returns_self_when_called_with_block_but_no_arguments 0.076 +Array#permutation_yields_all_permutations_of_given_length_to_the_block_then_returns_self_when_called_with_block_and_argument 0.072 +Array#permutation_returns_the_empty_permutation_([[]])_when_the_given_length_is_0 0.029 +Array#permutation_returns_the_empty_permutation([])_when_called_on_an_empty_Array 0.029 +Array#permutation_returns_no_permutations_when_the_given_length_has_no_permutations 0.029 +Array#permutation_handles_duplicate_elements_correctly 0.081 +Array#permutation_handles_nested_Arrays_correctly 0.085 +Array#permutation_truncates_Float_arguments 0.063 +Array#permutation_returns_an_Enumerator_which_works_as_expected_even_when_the_array_was_modified 0.056 +Array#permutation_generates_from_a_defensive_copy,_ignoring_mutations 0.038 +``` + + +## Parser + +Opal relies on the `parser` gem, see debug/development documentation there to know more about its internals: https://whitequark.github.io/parser/. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3d615c89 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2013-2021 by Adam Beynon and the Opal contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index bb94e3c6..6f261f94 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,279 @@ -# Opal CDN distribution +

+ +
+ Opal
+ Opal-Ruby 💛 JavaScript +

-## URL scheme +

+ Opal is a Ruby to JavaScript source-to-source compiler.
+ It also has an implementation of the Ruby corelib and stdlib.
+

- //cdn.opalrb.com/opal//opal.js - //cdn.opalrb.com/opal//opal.min.js - //cdn.opalrb.com/opal//opal.min.js.gz +

+ Community:
+ Stack Overflow + Backers on Open Collective + Sponsors on Open Collective + Slack + Documentation + +
+ Code:
+ Gem Version + Build Status + Code Climate + Coverage Status + +
+ Sponsors: +
Nebulab: Open Source Fridays +

-Where `` is the desired version number or `current`, examples: +## Usage - //cdn.opalrb.com/opal/0.10.1/opal.js - //cdn.opalrb.com/opal/0.9.4/date.min.js - //cdn.opalrb.com/opal/current/base64.min.js.gz +See the website for more detailed instructions and guides for Rails, jQuery, Sinatra, rack, CDN, etc. [https://opalrb.com](https://opalrb.com). +### Compiling Ruby code with the CLI (Command Line Interface) -## Embedding in your HTML +Contents of `app.rb`: + +```ruby +puts 'Hello world!' +``` + +Then from the terminal + +```bash +$ opal --compile app.rb > app.js # The Opal runtime is included by default + # but can be skipped with the --no-opal flag +``` + +The resulting JavaScript file can be used normally from an HTML page: ```html - - - - - - - - - - - +``` + +Be sure to set the page encoding to `UTF-8` inside your `` tag as follows: + +```html + - - - - -

Opal CDN distribution

+ + + + … + + + … + + +``` -

URL scheme

+Just open this page in a browser and check the JavaScript console. -
//cdn.opalrb.com/opal/<VERSION>/opal.js
-//cdn.opalrb.com/opal/<VERSION>/opal.min.js
-//cdn.opalrb.com/opal/<VERSION>/opal.min.js.gz
-
-

Where <VERSION> is the desired version number or current, examples:

+### Compiling Ruby code from Ruby -
//cdn.opalrb.com/opal/0.10.1/opal.js
-//cdn.opalrb.com/opal/0.9.4/date.min.js
-//cdn.opalrb.com/opal/current/base64.min.js.gz
-
+`Opal.compile` is a simple interface to just compile a string of Ruby into a +string of JavaScript code. -

License

+```ruby +Opal.compile("puts 'wow'") # => "(function() { ... self.$puts("wow"); ... })()" +``` -

See http://opalrb.com.

- - - } - #]]> - - +Running this by itself is not enough; you need the opal runtime/corelib. + +#### Using Opal::Builder + +`Opal::Builder` can be used to build the runtime/corelib into a string. + +```ruby +Opal::Builder.build('opal') #=> "(function() { ... })()" +``` + +or to build an entire app including dependencies declared with `require`: + +```ruby +builder = Opal::Builder.new +builder.build_str('require "opal"; puts "wow"', '(inline)') +File.write 'app.js', builder.to_s +``` + + +### Compiling Ruby code from HTML (or using it as you would with inline JavaScript) + +`opal-parser` allows you to *eval* Ruby code directly from your HTML (and from Opal) files without needing any other building process. + +So you can create a file like the one below, and start writing ruby for +your web applications. + + +```html + + + + + + + + + + + + ``` -## Updating +Just open this page and check the JavaScript console. + +**NOTE**: Although this is possible, this is not really recommended for +production and should only be used as a quick way to get your hands +on opal. + +## Running tests + +Setup the project: + + $ bin/setup + +The test suite can be run using: + + $ bundle exec rake + +This will command will run all RSpec and MSpec examples in sequence. + +#### Automated runs -### Opal +A `Guardfile` with decent mappings between specs and lib/corelib/stdlib files is in place. +Run `bundle exec guard -i` to start `guard`. -From the `opal` dir, assuming there's a checkout of the `gh-pages` branch of `opal-cdn` in the `cdn/` folder: - $ rake dist DIR=cdn/opal/0.7.0.dev - $ rake dist DIR=cdn/opal/master +### MSpec -### External libraries +[MSpec][] tests can be run with: - $ opal-build -ropal/browser browser > cdn/external/0.6.2/opal-browser-0.2.0.beta1.js - $ opal-build -ropal-jquery opal-jquery > cdn/external/0.6.2/opal-jquery-0.2.0.js + $ rake mspec + +Alternatively, you can just load up a rack instance using `rackup`, and +visit `http://localhost:9292/` in any web browser. + + +### RSpec + +[RSpec][] tests can be run with: + + $ rake rspec + + +## Code Overview + +What code is supposed to run where? + +* `lib/` code runs inside your Ruby env. It compiles Ruby to JavaScript. +* `opal/` is the runtime+corelib for our implementation (runs in browser). +* `stdlib/` is our implementation of Ruby's stdlib. It is optional (runs in browser). + +### lib/ + +The `lib` directory holds the **Opal parser/compiler** used to compile Ruby +into JavaScript. It is also built ready for the browser into `opal-parser.js` +to allow compilation in any JavaScript environment. + +### opal/ + +This directory holds the **Opal runtime and corelib** implemented in Ruby and +JavaScript. + +### stdlib/ + +Holds the **stdlib currently supported by Opal**. This includes `Observable`, +`StringScanner`, `Date`, etc. + +## Browser support + +* Internet Explorer 11 +* Firefox (Current - 1) or Current +* Chrome (Current - 1) or Current +* Safari (Current - 1) or Current +* Opera (Current - 1) or Current + +Any problems encountered using the browsers listed above should be reported as bugs. + +(Current - 1) or Current denotes that we support the current stable version of +the browser and the version that preceded it. For example, if the current +version of a browser is 24.x, we support the 24.x and 23.x versions. + +12.1x or (Current - 1) or Current denotes that we support Opera 12.1x as well +as the last 2 versions of Opera. For example, if the current Opera version is 20.x, +then we support Opera 12.1x, 19.x and 20.x but not Opera 15.x through 18.x. + +## Contributors + +This project exists thanks to all the people who contribute. [![contributors](https://opencollective.com/opal/contributors.svg?width=890&button=false")](https://github.com/opal/opal/graphs/contributors) + +## Versioning + +Opal will broadly follow semver as a version policy, trying to bump the major version when introducing breaking changes. +Being a language implementation we're also aware that there's a fine line between what can be considered breaking and what is expected to be "safe" or just "additive". Moving forward we'll attempt to better clarify what interfaces are meant to be public and what should be considered private. + +## Backers + +Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/opal#backer)] + +Become a Backer Button + + + + + + + + + + + +## Sponsors + +### Donations + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/opal#sponsor)] + +Become a Sponsor Button + +### Sponsored Contributions + +Nebulab Logo ## License -See [http://opalrb.com](http://opalrb.com). +(The MIT License) + +Copyright (C) 2013-2021 by Adam Beynon and the Opal contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +[MSpec]: https://github.com/ruby/mspec#readme +[RSpec]: https://github.com/rspec/rspec#readme diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..9ff21877 --- /dev/null +++ b/Rakefile @@ -0,0 +1,12 @@ +# FIXME: there must be a better way +Encoding.default_external = 'utf-8' + +import 'tasks/github.rake' +import 'tasks/testing.rake' +import 'tasks/building.rake' +import 'tasks/linting.rake' +import 'tasks/benchmarking.rake' +import 'tasks/releasing.rake' +import 'tasks/performance.rake' + +task :default => [:rspec, :mspec, :minitest] diff --git a/UNRELEASED.md b/UNRELEASED.md new file mode 100644 index 00000000..0b921db2 --- /dev/null +++ b/UNRELEASED.md @@ -0,0 +1,32 @@ +### Added + +- Introduce timezone support for Time (#2394) +- DateTime and Date refactor (#2398) +- Implement `Number#prev_float`/`#next_float` (#2404) + +### Changed + +- Move Math IE11-supporting polyfills to a separate file (#2395) + +### Internal + +- Improve performance of argument coertion, fast-track `Integer`, `String`, and calling the designed coertion method (#2383) +- Optimize `Array#[]=` by moving the implementation to JavaScript and inlining type checks (#2383) +- Optimize internal runtime passing of block-options (#2383) + +### Fixed + +- Fix `Regexp.new`, previously `\A` and `\z` didn't match beginning and end of input (#2079) +- Fix exception during `Hash#each` and `Hash#each_key` if keys get deleted during the loop (#2403) + +### Internal + +- Rewriters refactor, fix interaction between cache and iverted runner (#2400) + + diff --git a/benchmark-ips/README.md b/benchmark-ips/README.md new file mode 100644 index 00000000..75b8f4f3 --- /dev/null +++ b/benchmark-ips/README.md @@ -0,0 +1,6 @@ +Usage: + + bundle exec rake bench:ips + bundle exec rake bench:ips FILE=benchmark-ips/bm_while_true_vs_loop.rb + +For details see `tasks/benchmarking.rake` diff --git a/benchmark-ips/bm_array_pop_1.rb b/benchmark-ips/bm_array_pop_1.rb new file mode 100644 index 00000000..cab4658d --- /dev/null +++ b/benchmark-ips/bm_array_pop_1.rb @@ -0,0 +1,8 @@ +Benchmark.ips do |x| + x.report('pop(1)') do + a = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] + a.pop(1) + end + + x.compare! +end diff --git a/benchmark-ips/bm_array_shift.rb b/benchmark-ips/bm_array_shift.rb new file mode 100644 index 00000000..f32d6e9b --- /dev/null +++ b/benchmark-ips/bm_array_shift.rb @@ -0,0 +1,7 @@ +Benchmark.ips do |x| + x.report("shift no arg") do + a = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] + a.shift + end + x.compare! +end diff --git a/benchmark-ips/bm_array_unshift.rb b/benchmark-ips/bm_array_unshift.rb new file mode 100644 index 00000000..73839d76 --- /dev/null +++ b/benchmark-ips/bm_array_unshift.rb @@ -0,0 +1,7 @@ +Benchmark.ips do |x| + x.report("unshift") do + a = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] + a.unshift('aaa', 'bbb', 'ccc') + end + x.compare! +end diff --git a/benchmark-ips/bm_block_vs_yield.rb b/benchmark-ips/bm_block_vs_yield.rb new file mode 100644 index 00000000..222d137e --- /dev/null +++ b/benchmark-ips/bm_block_vs_yield.rb @@ -0,0 +1,21 @@ +module BmBlockVsYield + def self._block(&block) + block.call + end + + def self._yield + yield + end +end + +Benchmark.ips do |x| + x.report('block') do + BmBlockVsYield._block { 1+1 } + end + + x.report('yield') do + BmBlockVsYield._yield { 1+1 } + end + + x.compare! +end diff --git a/benchmark-ips/bm_case.rb b/benchmark-ips/bm_case.rb new file mode 100644 index 00000000..1b7b45a6 --- /dev/null +++ b/benchmark-ips/bm_case.rb @@ -0,0 +1,33 @@ +Benchmark.ips do |x| + obj = Object.new + x.report("numeric statement") do + case 1 + when 4 then 4 + when 3 then 3 + when 2 then 2 + when 1 then 1 + end + nil + end + x.report("statement") do + case 1 + when 4 then 4 + when 3 then 3 + when 2 then 2 + when obj then :obj + when 1 then 1 + end + nil + end + x.report("expression") do + case 1 + when 4 then 4 + when 3 then 3 + when 2 then 2 + when obj then :obj + when 1 then 1 + end + end + + x.compare! +end diff --git a/benchmark-ips/bm_constants_lookup.rb b/benchmark-ips/bm_constants_lookup.rb new file mode 100644 index 00000000..6919d35a --- /dev/null +++ b/benchmark-ips/bm_constants_lookup.rb @@ -0,0 +1,13 @@ +module A + module B + module C + Benchmark.ips do |x| + x.report("Kernel") { Kernel } + x.report("::Kernel") { ::Kernel } + x.report("B") { B } + x.report("B::C") { B::C } + x.compare! + end + end + end +end diff --git a/benchmark-ips/bm_is_number.rb b/benchmark-ips/bm_is_number.rb new file mode 100644 index 00000000..aa0a8409 --- /dev/null +++ b/benchmark-ips/bm_is_number.rb @@ -0,0 +1,29 @@ +# Why .$$is_number is better than isNaN: +# +# +# Warming up -------------------------------------- +# .$$is_number 106.722k i/100ms +# isNaN() 105.040k i/100ms +# obj.$$is_number 106.864k i/100ms +# isNaN(obj) 89.287k i/100ms +# Calculating ------------------------------------- +# .$$is_number 12.052M (± 6.6%) i/s - 59.978M in 5.002614s +# isNaN() 12.338M (± 5.4%) i/s - 61.448M in 4.997957s +# obj.$$is_number 12.514M (± 6.8%) i/s - 62.302M in 5.005715s +# isNaN(obj) 4.211M (± 5.9%) i/s - 20.982M in 5.001643s +# +# Comparison: +# obj.$$is_number: 12513664.2 i/s +# isNaN(): 12338259.3 i/s - same-ish: difference falls within error +# .$$is_number: 12051756.8 i/s - same-ish: difference falls within error +# isNaN(obj): 4211175.7 i/s - 2.97x slower +# +Benchmark.ips do |x| + number = 123 + number_obj = 123.itself + x.report(".$$is_number") { number.JS['$$is_number'] } + x.report("isNaN()") { `!isNaN(number)` } + x.report("obj.$$is_number") { number_obj.JS['$$is_number'] } + x.report("isNaN(obj)") { `!isNaN(number_obj)` } + x.compare! +end diff --git a/benchmark-ips/bm_js_symbols_vs_strings.rb b/benchmark-ips/bm_js_symbols_vs_strings.rb new file mode 100644 index 00000000..36f9de34 --- /dev/null +++ b/benchmark-ips/bm_js_symbols_vs_strings.rb @@ -0,0 +1,58 @@ +Benchmark.ips do |x| + %x{ + const c_foo = 'foo' + const v_foo = 'foo' + const cfoo = Symbol('foo') + var vfoo = Symbol('foo') + const cgfoo = Symbol.for('foo') + var vgfoo = Symbol.for('foo') + + var o = {} + o[cfoo] = 1 + o[cgfoo] = 1 + o[c_foo] = 1 + o[vfoo] = 1 + + let a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0, a7 = 0, a8 = 0 + } + + x.report('const string ref') do + `a1 += o[c_foo]` + end + + x.report('var string ref') do + `a2 += o[v_foo]` + end + + x.report('live global symbol') do + `a3 += o[Symbol.for('foo')]` + end + + x.report('const global symbol') do + `a4 += o[cgfoo]` + end + + x.report('var global symbol') do + `a5 += o[vgfoo]` + end + + x.report('const symbol') do + `a6 += o[cfoo]` + end + + x.report('var symbol') do + `a6 += o[vfoo]` + end + + x.report('ident') do + `a7 += o.foo` + end + + x.report('live string') do + `a8 += o['foo']` + end + + x.time = 10 + + x.compare! +end diff --git a/benchmark-ips/bm_symbol_to_proc.rb b/benchmark-ips/bm_symbol_to_proc.rb new file mode 100644 index 00000000..c666d9b6 --- /dev/null +++ b/benchmark-ips/bm_symbol_to_proc.rb @@ -0,0 +1,19 @@ +# https://github.com/opal/opal/issues/1659#issuecomment-298222232 + +Benchmark.ips do |x| + a = [] + + 50.times do |i| + a << %(#{i}\n) + end + + x.report('map block') do + a.map {|it| it.chomp } + end + + x.report('map symbol') do + a.map(&:chomp) + end + + x.compare! +end diff --git a/benchmark-ips/bm_truthy.rb b/benchmark-ips/bm_truthy.rb new file mode 100644 index 00000000..bebd2ca3 --- /dev/null +++ b/benchmark-ips/bm_truthy.rb @@ -0,0 +1,30 @@ +Benchmark.ips do |x| + %x{ + // Old version truthy logic + var old_version = function(x) { return x !== nil && x != null && (!x.$$is_boolean || x == true); } + + // New version truthy logic + var new_version_1 = function(val) { return undefined !== val && null !== val && false !== val && nil !== val && (!(val instanceof Boolean) || true === val.valueOf()); } + + // Alternative new version truthy logic + var new_version_2 = function(val) { return undefined !== val && null !== val && false !== val && nil !== val && !(val instanceof Boolean && false === val.valueOf()); } + + // Alternative new version, nil&false first + var new_version_3 = function(val) { return false !== val && nil !== val && undefined !== val && null !== val && !(val instanceof Boolean && false === val.valueOf()); } + + // Alternative new version truthy logic that unsupports boxed booleans + var new_unboxed = function(val) { return undefined !== val && null !== val && false !== val && nil !== val; } + } + + values = [123,243,35,"sd",false,nil,123413234,120412,0,1234.1234,0.34,false,false,true,"sadfasf","","0",13,123,nil,Object.new,[]] + + x.time = 32 + + x.report('old_version') { values.map(&`old_version`) } + x.report('new_version_1') { values.map(&`new_version_1`) } + x.report('new_version_2') { values.map(&`new_version_2`) } + x.report('new_version_3') { values.map(&`new_version_3`) } + x.report('new_unboxed') { values.map(&`new_unboxed`) } + + x.compare! +end diff --git a/benchmark-ips/bm_while_true_vs_loop.rb b/benchmark-ips/bm_while_true_vs_loop.rb new file mode 100644 index 00000000..d923d241 --- /dev/null +++ b/benchmark-ips/bm_while_true_vs_loop.rb @@ -0,0 +1,19 @@ +Benchmark.ips do |x| + x.report('while true') do + n = 0 + while true + n += 1 + break if n == 10000 + end + end + + x.report('loop') do + n = 0 + loop do + n += 1 + break if n == 10000 + end + end + + x.compare! +end diff --git a/benchmark-ips/class_shovel_vs_singleton_class.rb b/benchmark-ips/class_shovel_vs_singleton_class.rb new file mode 100644 index 00000000..4f755bd9 --- /dev/null +++ b/benchmark-ips/class_shovel_vs_singleton_class.rb @@ -0,0 +1,16 @@ +o = nil +Benchmark.ips do |x| + x.report('shovel') do + o = Object.new + class << o + attr_accessor :foo + end + end + + x.report('singleton_class') do + o2 = Object.new + o2.singleton_class.attr_accessor :foo + end + + x.compare! +end diff --git a/benchmark/benchmarks b/benchmark/benchmarks new file mode 100644 index 00000000..7d119518 --- /dev/null +++ b/benchmark/benchmarks @@ -0,0 +1,103 @@ +test/cruby/benchmark/bm_app_answer.rb +#[error] test/cruby/benchmark/bm_app_aobench.rb +#[error] test/cruby/benchmark/bm_app_erb.rb +test/cruby/benchmark/bm_app_factorial.rb +test/cruby/benchmark/bm_app_fib.rb +#[too long] test/cruby/benchmark/bm_app_lc_fizzbuzz.rb +#[error] test/cruby/benchmark/bm_app_mandelbrot.rb +#[too long] test/cruby/benchmark/bm_app_pentomino.rb +#[longish] test/cruby/benchmark/bm_app_raise.rb +test/cruby/benchmark/bm_app_strconcat.rb +test/cruby/benchmark/bm_app_tak.rb +test/cruby/benchmark/bm_app_tarai.rb +#[error] test/cruby/benchmark/bm_app_uri.rb +#[error] test/cruby/benchmark/bm_hash_aref_flo.rb +test/cruby/benchmark/bm_hash_aref_miss.rb +test/cruby/benchmark/bm_hash_aref_str.rb +#[error] test/cruby/benchmark/bm_hash_aref_sym_long.rb +#[error] test/cruby/benchmark/bm_hash_aref_sym.rb +test/cruby/benchmark/bm_hash_flatten.rb +#[error] test/cruby/benchmark/bm_hash_ident_flo.rb +#[error] test/cruby/benchmark/bm_hash_ident_num.rb +#[error] test/cruby/benchmark/bm_hash_ident_obj.rb +#[error] test/cruby/benchmark/bm_hash_ident_str.rb +#[error] test/cruby/benchmark/bm_hash_ident_sym.rb +test/cruby/benchmark/bm_hash_keys.rb +test/cruby/benchmark/bm_hash_shift.rb +test/cruby/benchmark/bm_hash_values.rb +test/cruby/benchmark/bm_loop_for.rb +#[error] test/cruby/benchmark/bm_loop_generator.rb +test/cruby/benchmark/bm_loop_times.rb +test/cruby/benchmark/bm_loop_whileloop2.rb +test/cruby/benchmark/bm_loop_whileloop.rb +#[error] test/cruby/benchmark/bm_securerandom.rb +test/cruby/benchmark/bm_so_ackermann.rb +#[<30] test/cruby/benchmark/bm_so_array.rb +#[error] test/cruby/benchmark/bm_so_binary_trees.rb +#[error] test/cruby/benchmark/bm_so_concatenate.rb +#[error] test/cruby/benchmark/bm_so_count_words.rb +#[longish] test/cruby/benchmark/bm_so_exception.rb +#[longish] test/cruby/benchmark/bm_so_fannkuch.rb +#[error] test/cruby/benchmark/bm_so_fasta.rb +#[error] test/cruby/benchmark/bm_so_k_nucleotide.rb +test/cruby/benchmark/bm_so_lists.rb +#[writes to stdout] test/cruby/benchmark/bm_so_mandelbrot.rb +test/cruby/benchmark/bm_so_matrix.rb +#[error] test/cruby/benchmark/bm_so_meteor_contest.rb +#[error] test/cruby/benchmark/bm_so_nbody.rb +test/cruby/benchmark/bm_so_nested_loop.rb +#[error] test/cruby/benchmark/bm_so_nsieve_bits.rb +#[error] test/cruby/benchmark/bm_so_nsieve.rb +test/cruby/benchmark/bm_so_object.rb +#[error] test/cruby/benchmark/bm_so_partial_sums.rb +#[error] test/cruby/benchmark/bm_so_pidigits.rb +test/cruby/benchmark/bm_so_random.rb +#[error] test/cruby/benchmark/bm_so_reverse_complement.rb +#[<30] test/cruby/benchmark/bm_so_sieve.rb +#[error] test/cruby/benchmark/bm_so_spectralnorm.rb +test/cruby/benchmark/bm_vm1_attr_ivar.rb +test/cruby/benchmark/bm_vm1_attr_ivar_set.rb +test/cruby/benchmark/bm_vm1_block.rb +test/cruby/benchmark/bm_vm1_const.rb +test/cruby/benchmark/bm_vm1_ensure.rb +test/cruby/benchmark/bm_vm1_float_simple.rb +test/cruby/benchmark/bm_vm1_gc_short_lived.rb +test/cruby/benchmark/bm_vm1_ivar.rb +test/cruby/benchmark/bm_vm1_ivar_set.rb +test/cruby/benchmark/bm_vm1_length.rb +test/cruby/benchmark/bm_vm1_lvar_init.rb +test/cruby/benchmark/bm_vm1_lvar_set.rb +test/cruby/benchmark/bm_vm1_neq.rb +test/cruby/benchmark/bm_vm1_not.rb +test/cruby/benchmark/bm_vm1_rescue.rb +test/cruby/benchmark/bm_vm1_simplereturn.rb +test/cruby/benchmark/bm_vm1_swap.rb +test/cruby/benchmark/bm_vm1_yield.rb +test/cruby/benchmark/bm_vm2_array.rb +test/cruby/benchmark/bm_vm2_bigarray.rb +test/cruby/benchmark/bm_vm2_bighash.rb +test/cruby/benchmark/bm_vm2_case.rb +test/cruby/benchmark/bm_vm2_defined_method.rb +test/cruby/benchmark/bm_vm2_dstr.rb +#[error] test/cruby/benchmark/bm_vm2_eval.rb +test/cruby/benchmark/bm_vm2_method_missing.rb +test/cruby/benchmark/bm_vm2_method.rb +test/cruby/benchmark/bm_vm2_method_with_block.rb +test/cruby/benchmark/bm_vm2_newlambda.rb +test/cruby/benchmark/bm_vm2_poly_method_ov.rb +test/cruby/benchmark/bm_vm2_poly_method.rb +test/cruby/benchmark/bm_vm2_proc.rb +#[longish] test/cruby/benchmark/bm_vm2_raise1.rb +#[longish] test/cruby/benchmark/bm_vm2_raise2.rb +#[error] test/cruby/benchmark/bm_vm2_regexp.rb +test/cruby/benchmark/bm_vm2_send.rb +test/cruby/benchmark/bm_vm2_struct_big_aref_hi.rb +test/cruby/benchmark/bm_vm2_struct_big_aref_lo.rb +test/cruby/benchmark/bm_vm2_struct_big_aset.rb +test/cruby/benchmark/bm_vm2_struct_small_aref.rb +test/cruby/benchmark/bm_vm2_struct_small_aset.rb +test/cruby/benchmark/bm_vm2_super.rb +test/cruby/benchmark/bm_vm2_unif1.rb +test/cruby/benchmark/bm_vm2_zsuper.rb +#[too long] test/cruby/benchmark/bm_vm3_backtrace.rb +test/cruby/benchmark/bm_vm3_clearmethodcache.rb diff --git a/benchmark/bm_array_flatten.rb b/benchmark/bm_array_flatten.rb new file mode 100644 index 00000000..c51fa499 --- /dev/null +++ b/benchmark/bm_array_flatten.rb @@ -0,0 +1,9 @@ +a = [] + +1000.times do |i| + a << [i] +end + +1000.times do + a.flatten +end diff --git a/benchmark/bm_array_intersection_numbers.rb b/benchmark/bm_array_intersection_numbers.rb new file mode 100644 index 00000000..758bb079 --- /dev/null +++ b/benchmark/bm_array_intersection_numbers.rb @@ -0,0 +1,7 @@ +a1 = [4768, 4964, 4266, 4872, 4231, 4017, 4565, 4793, 4298, 4135, 4639, 4780, 4237, 4548, 4655, 4153, 4654, 4922, 4563, 4042, 4329, 4699, 4352, 4127, 4544, 4906, 4814, 4948, 4977, 4830, 4405, 4642, 4666, 4402, 4679, 4465, 4401, 4155, 4767, 4510, 4747, 4993, 4508, 4697, 4758, 4133, 4348, 4200, 4442, 4970, 4452, 4041, 4103, 4567, 4937, 4047, 4933, 4121, 4860, 4659, 4221, 4312, 4583, 4473, 4973, 4262, 4630, 4123, 4139, 4289, 4147, 4222, 4050, 4019, 4454, 4253, 4552, 4947, 4725, 4457, 4929, 4021, 4502, 4307, 4576, 4124, 4586, 4610, 4027, 4572, 4926, 4753, 4185, 4382, 4394, 4923, 4186, 4254, 4012, 4417, 4556, 4349, 4550, 4330, 4938, 4985, 4778, 4716, 4924, 4045, 4358, 4189, 4591, 4213, 4851, 4825, 4260, 4198, 4342, 4824, 4333, 4244, 4752, 4994, 4488, 4532, 4082, 4595, 4098, 4436, 4540, 4267, 4407, 4998, 4751, 4535, 4861, 4819, 4419, 4031, 4029, 4453, 4698, 4965, 4450, 4668, 4036, 4300, 4519, 4281, 4981, 4818, 4939, 4378, 4140, 4841, 4249, 4290, 4388, 4878, 4884, 4235, 4515, 4638, 4410, 4054, 4383, 4238, 4870, 4295, 4804, 4308, 4614, 4105, 4053, 4446, 4757, 4971, 4637, 4831, 4193, 4912, 4000, 4187, 4606, 4566, 4169, 4641, 4749, 4729, 4928, 4601, 4949, 4210, 4313, 4647, 4495, 4460, 4621, 4605, 4694, 4317, 4226, 4263, 4016, 4997, 4940, 4715, 4907, 4620, 4934, 4996, 4955, 4688, 4304, 4220, 4882, 4772, 4536, 4815, 4693, 4469, 4276, 4409, 4071, 4224, 4020, 4629, 4865, 4813, 4366, 4622, 4129, 4533, 4634, 4564, 4087, 4386, 4161, 4265, 4711, 4009, 4376, 4781, 4837, 4112, 4915, 4592, 4658, 4025, 4987, 4291, 4477, 4503, 4437, 4111, 4707, 4879, 4611, 4549, 4078, 4044, 4853, 4835, 4463, 4577, 4008, 4233, 4741, 4384, 4225, 4024, 4726, 4743, 4160, 4180, 4722, 4609, 4114, 4834, 4742, 4662, 4984, 4299, 4060, 4498, 4755, 4320, 4874, 4528, 4216, 4852, 4951, 4958, 4283, 4239, 4476, 4644, 4143, 4104, 4455, 4126, 4950, 4663, 4013, 4931, 4850, 4242, 4130, 4623, 4871, 4014, 4854, 4293, 4512, 4166, 4740, 4735, 4150, 4651, 4172, 4836, 4530, 4664, 4429, 4511, 4558, 4676, 4085, 4074, 4580, 4794, 4379, 4310, 4817, 4966, 4848, 4202, 4336, 4608, 4351, 4396, 4652, 4033, 4188, 4431, 4916, 4259, 4607, 4816, 4810, 4627, 4527, 4560, 4728, 4589, 4274, 4809, 4790, 4398, 4414, 4516, 4581, 4919, 4665, 4331, 4978, 4543, 4877, 4974, 4284, 4004, 4177, 4466, 4116, 4217, 4901, 4372, 4137, 4806, 4264, 4497, 4294, 4787, 4212, 4215, 4115, 4782, 4739, 4821, 4125, 4505, 4230, 4399, 4395, 4079, 4867, 4381, 4706, 4695, 4404, 4691, 4075, 4353, 4301, 4876, 4731, 4523, 4246, 4529, 4412, 4784, 4449, 4229, 4616, 4158, 4002, 4318, 4377, 4205, 4911, 4777, 4792, 4271, 4763, 4141, 4287, 4890, 4279, 4829, 4646, 4840, 4089, 4880, 4067, 4918, 4059, 4109, 4164, 4863, 4883, 4909, 4361, 4174, 4960, 4302, 4003, 4236, 4846, 4034, 4324, 4513, 4765, 4596, 4900, 4007, 4603, 4474, 4439, 4805, 4015, 4496, 4953, 4363, 4551, 4459, 4063, 4983, 4881, 4365, 4604, 4587, 4798, 4005, 4163, 4421, 4471, 4826, 4144, 4635, 4600, 4913, 4640, 4247, 4766, 4779, 4280, 4391, 4891, 4636, 4546, 4683, 4181, 4081, 4862, 4458, 4037, 4321, 4786, 4717, 4628, 4154, 4326, 4032, 4873, 4151, 4905, 4270, 4156, 4733, 4980, 4866, 4325, 4055, 4467, 4480, 4286, 4191, 4762, 4322, 4574, 4022, 4056, 4770, 4451, 4448, 4845, 4341, 4433, 4245, 4684, 4671, 4093, 4920, 4272, 4745, 4799, 4761, 4250, 4578, 4347, 4499, 4526, 4369, 4162, 4537, 4434, 4893, 4120, 4962, 4667, 4525, 4091, 4462, 4182, 4738, 4935, 4173, 4490, 4571, 4424, 4894, 4051, 4214, 4823, 4096, 4206, 4598, 4943, 4701, 4649, 4807, 4107, 4435, 4456, 4083, 4612, 4721, 4472, 4146, 4925, 4340, 4789, 4277, 4375, 4211, 4427, 4547, 4690, 4613, 4727, 4006, 4203, 4430, 4223, 4039, 4932, 4296, 4108, 4278, 4832, 4422, 4917, 4470, 4183, 4887, 4076, 4485, 4597, 4443, 4257, 4991, 4944, 4196, 4672, 4397, 4097, 4119, 4077, 4773, 4602, 4538, 4479, 4968, 4159, 4539, 4956, 4710, 4812, 4902, 4569, 4954, 4385, 4128, 4936, 4416, 4148, 4632, 4759, 4117, 4896, 4392, 4864, 4316, 4132, 4319, 4969, 4175, 4484, 4903, 4910, 4350, 4332, 4952, 4176, 4594, 4709, 4509, 4178, 4167, 4545, 4857, 4617, 4501, 4859, 4207, 4275, 4687, 4049, 4579, 4046, 4921, 4113, 4898, 4681, 4052, 4415, 4064, 4184, 4895, 4744, 4685, 4084, 4305, 4899, 4559, 4208, 4057, 4507, 4258, 4355, 4086, 4373, 4323, 4541, 4297, 4483, 4889, 4531, 4327, 4441, 4914, 4303, 4677, 4445, 4802, 4343, 4585, 4338, 4524, 4590, 4624, 4288, 4704, 4134, 4043, 4720, 4058, 4328, 4095, 4026, 4423, 4657, 4118, 4633, 4487, 4822, 4904, 4255, 4001, 4387, 4500, 4190, 4686, 4995, 4661, 4783, 4992, 4165, 4065, 4927, 4306, 4856, 4292, 4420, 4963, 4468, 4240, 4724, 4432, 4447, 4518, 4028, 4670, 4339, 4771, 4018, 4489, 4110, 4708, 4945, 4136, 4492, 4930, 4090, 4734, 4886, 4542, 4227, 4486, 4491, 4713, 4986, 4068, 4048, 4975, 4570, 4842, 4475, 4131, 4555, 4428, 4776, 4101, 4273, 4811, 4345, 5000, 4653, 4256, 4209, 4769, 4946, 4561, 4080, 4461, 4820, 4311, 4959, 4750, 4795, 4748, 4368, 4506, 4335, 4346, 4568, 4675, 4692, 4774, 4413, 4370, 4723, 4521, 4885, 4678, 4897, 4066, 4674, 4106, 4626, 4389, 4204, 4839, 4023, 4712, 4145, 4035, 4357, 4756, 4648, 4972, 4157, 4406, 4615, 4061, 4219, 4791, 4660, 4073, 4356, 4072, 4599, 4359, 4094, 4673, 4696, 4796, 4282, 4714, 4522, 4736, 4775, 4760, 4400, 4847, 4228, 4803, 4908, 4732, 4645, 4122, 4218, 4478, 4941, 4892, 4364, 4403, 4152, 4444, 4360, 4354, 4241, 4494, 4367, 4808, 4261, 4088, 4573, 4554, 4248, 4371, 4393, 4268, 4201, 4038, 4788, 4593, 4040, 4801, 4582, 4309, 4976, 4374, 4869, 4380, 4514, 4243, 4362, 4849, 4680, 4888, 4764, 4618, 4838, 4828, 4643, 4010, 4827, 4957, 4099, 4875, 4843, 4737, 4102, 4979, 4011, 4504, 4440, 4746, 4557, 4426, 4553, 4656, 4868, 4689, 4988, 4703, 4967, 4069, 4619, 4334, 4669, 4785, 4464, 4562, 4961, 4625, 4754, 4797, 4481, 4705, 4199, 4337, 4062, 4138, 4702, 4534, 4168, 4418, 4092, 4682, 4520, 4030, 4171, 4650, 4858, 4411, 4999, 4252, 4197, 4170, 4942, 4631, 4990, 4179, 4285, 4700, 4482, 4575, 4800, 4070, 4251, 4344, 4982, 4719, 4390, 4149, 4100, 4194, 4269, 4855, 4314, 4718, 4232, 4730, 4438, 4588, 4195, 4192, 4493, 4517, 4833, 4234, 4989, 4315, 4844, 4142, 4408, 4584, 4425] +a2 = [5650, 6274, 5600, 6197, 6324, 5850, 5630, 5955, 6343, 6233, 6065, 5637, 5561, 6500, 5565, 5845, 5916, 6229, 5857, 5747, 6419, 5936, 6363, 5773, 6399, 6350, 6172, 6494, 6042, 6013, 6132, 5887, 6215, 5837, 5663, 5695, 6453, 5698, 5941, 6186, 5902, 6116, 6487, 5945, 5694, 6392, 5605, 5524, 5884, 6470, 5503, 6458, 5910, 6469, 5645, 5540, 5505, 6136, 5715, 6306, 6164, 6406, 6120, 5919, 5592, 5595, 5684, 6464, 5958, 6060, 5862, 5672, 5670, 6211, 6321, 5654, 5516, 6278, 6084, 5867, 5577, 6379, 6139, 6472, 6251, 6460, 5831, 6133, 5772, 5788, 6260, 5580, 5912, 5865, 5616, 6153, 5567, 5709, 5963, 6489, 6344, 6113, 6409, 5987, 6141, 5508, 6093, 5723, 5883, 5829, 6086, 5774, 6026, 5601, 5859, 5517, 6252, 6412, 6481, 5828, 5556, 6234, 6416, 5562, 5992, 6045, 5559, 6309, 6109, 6273, 6407, 5743, 6338, 5706, 5719, 6430, 5693, 6247, 6450, 5710, 6015, 6429, 5607, 6056, 6495, 5613, 6370, 5671, 5751, 6237, 5748, 6217, 5977, 6194, 5511, 5599, 5624, 5923, 6452, 5841, 5798, 6025, 5879, 6420, 6177, 6294, 5871, 6105, 5822, 5770, 5724, 5754, 6063, 6291, 5529, 5921, 6018, 5856, 6058, 6372, 6361, 5889, 5899, 5555, 6454, 5960, 6411, 5512, 6069, 5913, 5502, 5821, 5965, 6475, 5697, 5523, 5676, 6076, 5648, 5769, 5948, 6493, 5683, 6200, 5651, 5653, 5885, 5667, 6404, 6432, 6226, 6102, 6213, 5796, 6462, 5811, 5764, 6100, 6073, 6117, 6147, 6373, 5777, 6221, 6184, 5553, 5731, 5536, 6288, 6204, 5586, 5707, 5753, 6362, 5602, 5924, 6231, 5832, 6264, 5968, 5597, 6467, 5946, 6212, 6275, 5509, 6156, 5582, 5816, 5909, 5791, 5952, 6442, 6474, 6023, 5939, 5649, 5531, 6259, 5994, 6388, 5776, 5641, 6068, 6477, 6220, 6286, 5897, 5873, 6381, 6339, 5652, 5589, 6302, 6227, 5544, 5793, 5892, 6488, 5506, 5876, 5781, 5576, 5521, 6331, 6131, 5617, 6332, 5801, 6107, 6463, 6457, 5802, 5737, 6104, 5550, 6253, 6368, 6050, 5766, 5534, 6224, 6401, 6303, 5786, 5735, 6282, 5596, 6459, 6122, 6492, 5854, 5988, 5549, 6318, 5840, 6178, 5640, 5752, 6040, 5665, 5755, 5535, 5721, 6088, 5914, 5689, 6256, 5838, 6021, 5674, 6028, 6223, 6189, 5886, 6232, 5878, 6424, 6413, 6482, 6155, 5638, 6160, 6440, 5571, 6037, 6323, 5959, 6468, 5826, 5682, 6327, 5514, 6390, 5510, 5870, 6108, 5722, 5934, 5998, 6402, 6348, 5718, 6471, 5942, 6029, 6185, 5926, 6386, 5940, 6443, 6230, 5855, 6349, 6059, 6276, 5740, 5996, 6238, 6287, 5812, 5578, 5658, 5525, 6380, 6095, 6112, 5925, 6246, 5985, 5692, 6261, 5734, 6337, 5966, 6004, 6151, 6161, 5917, 5863, 6300, 5732, 5547, 5851, 6295, 5787, 5864, 5545, 6356, 6175, 6154, 5680, 5799, 5500, 5969, 6301, 5622, 6071, 6030, 5655, 6299, 5519, 5818, 6064, 6054, 5646, 6166, 6272, 5610, 5705, 5956, 5820, 5920, 5581, 6268, 6027, 6074, 6087, 5668, 5794, 5880, 6173, 6434, 6374, 6008, 5807, 5739, 6307, 6437, 5619, 6451, 5618, 5628, 5932, 6235, 6190, 6225, 5629, 5911, 6257, 6410, 6304, 6140, 6395, 5817, 6284, 5927, 6010, 5639, 5758, 6098, 6051, 6239, 5979, 6281, 6417, 5903, 5675, 6456, 5795, 5527, 6242, 6387, 6090, 5623, 5890, 6322, 6418, 6110, 6254, 5620, 5537, 5573, 6359, 5612, 6325, 5513, 6044, 5918, 6473, 6148, 6341, 5543, 6448, 6101, 6280, 6222, 6438, 5981, 6152, 5532, 5626, 6491, 5591, 6170, 5953, 6115, 5744, 6179, 5632, 5861, 6421, 6377, 6245, 5852, 5835, 5625, 6289, 5657, 6111, 5768, 5504, 5741, 5606, 6480, 6167, 6096, 6005, 5522, 5974, 6435, 5643, 6290, 5780, 6444, 6083, 5989, 5893, 5539, 6347, 6016, 6210, 6391, 5789, 5967, 5778, 6035, 6476, 5836, 5702, 6003, 5881, 5714, 6002, 6024, 6203, 6119, 5656, 5691, 5944, 5935, 6046, 5763, 6032, 6266, 6250, 5997, 6207, 6092, 6103, 6043, 5999, 5725, 5552, 6007, 6314, 6159, 5844, 5633, 6269, 5720, 5961, 5583, 6446, 5877, 6171, 6199, 6315, 6271, 5756, 6497, 6383, 5704, 5585, 6144, 6384, 6426, 6285, 5611, 6439, 6351, 5574, 5609, 5905, 5538, 5824, 6149, 6036, 5728, 5515, 5929, 6422, 5644, 6366, 5900, 6354, 6121, 5669, 6394, 5703, 5978, 6022, 6085, 5604, 6436, 5688, 6079, 5767, 6378, 5541, 6398, 6265, 6174, 5809, 5819, 6428, 6163, 5660, 6342, 6097, 6128, 6114, 6183, 5685, 5711, 6277, 6089, 5584, 6201, 6305, 6427, 5975, 5642, 6048, 6091, 6130, 5673, 5621, 5993, 5528, 6353, 6345, 6241, 6041, 6137, 6019, 5810, 6385, 6000, 6169, 6298, 6078, 5699, 6358, 5588, 5546, 5678, 5627, 6106, 5785, 6055, 6425, 5906, 5928, 6415, 6182, 6075, 5962, 6052, 6382, 6145, 6129, 6498, 5904, 5779, 5520, 5784, 5783, 6334, 5970, 6205, 5847, 6441, 6066, 6365, 6176, 5849, 6371, 6326, 5686, 5708, 6180, 5814, 5636, 6431, 6405, 6070, 5869, 6077, 5738, 6080, 6496, 5950, 5806, 5782, 5827, 5896, 5598, 5746, 6014, 5742, 6465, 6123, 5964, 6038, 6218, 6020, 5727, 5888, 5530, 6389, 6061, 6483, 6031, 5901, 6393, 6466, 6320, 5666, 5805, 6168, 5986, 5833, 6143, 6181, 5635, 5681, 6447, 6047, 5570, 5898, 5560, 5931, 6126, 6053, 5823, 5566, 5526, 5858, 5548, 6209, 6336, 6011, 5587, 5677, 6082, 5891, 5839, 5874, 5579, 6214, 6397, 5568, 6263, 5991, 5972, 6081, 6490, 6267, 6310, 6248, 5937, 6216, 6333, 5608, 5875, 5551, 6445, 5983, 5848, 5954, 6262, 5762, 6146, 6191, 6206, 6355, 6244, 5868, 5980, 6423, 5922, 6099, 5933, 5614, 5713, 6317, 6312, 5984, 6255, 6187, 6162, 5930, 5690, 5813, 6192, 6400, 5533, 5973, 6150, 6308, 6313, 6125, 6124, 5733, 5951, 5957, 5662, 5765, 5501, 5894, 5797, 5729, 5730, 6403, 6033, 6455, 5895, 6017, 5712, 6219, 5615, 6208, 6198, 6157, 5634, 6408, 5947, 5745, 5971, 6228, 6296, 5843, 5804, 6293, 6202, 5716, 5846, 6461, 5569, 6006, 5603, 6135, 6360, 5717, 6193, 5792, 5775, 5507, 6243, 5872, 6499, 5736, 6158, 6340, 5995, 6311, 6258, 5938, 6479, 5572, 5882, 6195, 6297, 5943, 5825, 6328, 6330, 5679, 6319, 6236, 6485, 6414, 5908, 6001, 5558, 6396, 6486, 5757, 5803, 5700, 5593, 5866, 6433, 5726, 6240, 5830, 6449, 5575, 6478, 5564, 5915, 6034, 6072, 6484, 6375, 5976, 5631, 6138, 5659, 6346, 6118, 6279, 5554, 6283, 5800, 5594, 5701, 6292, 5842, 5518, 6335, 5750, 6196, 5749, 6329, 6369, 5760, 6134, 5661, 6188, 5542, 6127, 6062, 6352, 6270, 5761, 6165, 6376, 6049, 5687, 6364, 5696, 6367, 5990, 5771, 6057, 6094, 5815, 6039, 5759, 5949, 5563, 5590, 5853, 6009, 5907, 5834, 5982, 5664, 6316, 5557, 6067, 6249, 6142, 6357, 5790, 5647, 5808, 5860, 6012] + +1000.times do + x = a1 & a2 + y = a2 & a1 +end diff --git a/benchmark/bm_array_intersection_objects.rb b/benchmark/bm_array_intersection_objects.rb new file mode 100644 index 00000000..90c9dbed --- /dev/null +++ b/benchmark/bm_array_intersection_objects.rb @@ -0,0 +1,7 @@ +a1 = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] +a2 = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] + +1000.times do + x = a1 & a2 + y = a2 & a1 +end diff --git a/benchmark/bm_array_intersection_strings.rb b/benchmark/bm_array_intersection_strings.rb new file mode 100644 index 00000000..deafb427 --- /dev/null +++ b/benchmark/bm_array_intersection_strings.rb @@ -0,0 +1,7 @@ +a1 = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] +a2 = ['5650', '6274', '5600', '6197', '6324', '5850', '5630', '5955', '6343', '6233', '6065', '5637', '5561', '6500', '5565', '5845', '5916', '6229', '5857', '5747', '6419', '5936', '6363', '5773', '6399', '6350', '6172', '6494', '6042', '6013', '6132', '5887', '6215', '5837', '5663', '5695', '6453', '5698', '5941', '6186', '5902', '6116', '6487', '5945', '5694', '6392', '5605', '5524', '5884', '6470', '5503', '6458', '5910', '6469', '5645', '5540', '5505', '6136', '5715', '6306', '6164', '6406', '6120', '5919', '5592', '5595', '5684', '6464', '5958', '6060', '5862', '5672', '5670', '6211', '6321', '5654', '5516', '6278', '6084', '5867', '5577', '6379', '6139', '6472', '6251', '6460', '5831', '6133', '5772', '5788', '6260', '5580', '5912', '5865', '5616', '6153', '5567', '5709', '5963', '6489', '6344', '6113', '6409', '5987', '6141', '5508', '6093', '5723', '5883', '5829', '6086', '5774', '6026', '5601', '5859', '5517', '6252', '6412', '6481', '5828', '5556', '6234', '6416', '5562', '5992', '6045', '5559', '6309', '6109', '6273', '6407', '5743', '6338', '5706', '5719', '6430', '5693', '6247', '6450', '5710', '6015', '6429', '5607', '6056', '6495', '5613', '6370', '5671', '5751', '6237', '5748', '6217', '5977', '6194', '5511', '5599', '5624', '5923', '6452', '5841', '5798', '6025', '5879', '6420', '6177', '6294', '5871', '6105', '5822', '5770', '5724', '5754', '6063', '6291', '5529', '5921', '6018', '5856', '6058', '6372', '6361', '5889', '5899', '5555', '6454', '5960', '6411', '5512', '6069', '5913', '5502', '5821', '5965', '6475', '5697', '5523', '5676', '6076', '5648', '5769', '5948', '6493', '5683', '6200', '5651', '5653', '5885', '5667', '6404', '6432', '6226', '6102', '6213', '5796', '6462', '5811', '5764', '6100', '6073', '6117', '6147', '6373', '5777', '6221', '6184', '5553', '5731', '5536', '6288', '6204', '5586', '5707', '5753', '6362', '5602', '5924', '6231', '5832', '6264', '5968', '5597', '6467', '5946', '6212', '6275', '5509', '6156', '5582', '5816', '5909', '5791', '5952', '6442', '6474', '6023', '5939', '5649', '5531', '6259', '5994', '6388', '5776', '5641', '6068', '6477', '6220', '6286', '5897', '5873', '6381', '6339', '5652', '5589', '6302', '6227', '5544', '5793', '5892', '6488', '5506', '5876', '5781', '5576', '5521', '6331', '6131', '5617', '6332', '5801', '6107', '6463', '6457', '5802', '5737', '6104', '5550', '6253', '6368', '6050', '5766', '5534', '6224', '6401', '6303', '5786', '5735', '6282', '5596', '6459', '6122', '6492', '5854', '5988', '5549', '6318', '5840', '6178', '5640', '5752', '6040', '5665', '5755', '5535', '5721', '6088', '5914', '5689', '6256', '5838', '6021', '5674', '6028', '6223', '6189', '5886', '6232', '5878', '6424', '6413', '6482', '6155', '5638', '6160', '6440', '5571', '6037', '6323', '5959', '6468', '5826', '5682', '6327', '5514', '6390', '5510', '5870', '6108', '5722', '5934', '5998', '6402', '6348', '5718', '6471', '5942', '6029', '6185', '5926', '6386', '5940', '6443', '6230', '5855', '6349', '6059', '6276', '5740', '5996', '6238', '6287', '5812', '5578', '5658', '5525', '6380', '6095', '6112', '5925', '6246', '5985', '5692', '6261', '5734', '6337', '5966', '6004', '6151', '6161', '5917', '5863', '6300', '5732', '5547', '5851', '6295', '5787', '5864', '5545', '6356', '6175', '6154', '5680', '5799', '5500', '5969', '6301', '5622', '6071', '6030', '5655', '6299', '5519', '5818', '6064', '6054', '5646', '6166', '6272', '5610', '5705', '5956', '5820', '5920', '5581', '6268', '6027', '6074', '6087', '5668', '5794', '5880', '6173', '6434', '6374', '6008', '5807', '5739', '6307', '6437', '5619', '6451', '5618', '5628', '5932', '6235', '6190', '6225', '5629', '5911', '6257', '6410', '6304', '6140', '6395', '5817', '6284', '5927', '6010', '5639', '5758', '6098', '6051', '6239', '5979', '6281', '6417', '5903', '5675', '6456', '5795', '5527', '6242', '6387', '6090', '5623', '5890', '6322', '6418', '6110', '6254', '5620', '5537', '5573', '6359', '5612', '6325', '5513', '6044', '5918', '6473', '6148', '6341', '5543', '6448', '6101', '6280', '6222', '6438', '5981', '6152', '5532', '5626', '6491', '5591', '6170', '5953', '6115', '5744', '6179', '5632', '5861', '6421', '6377', '6245', '5852', '5835', '5625', '6289', '5657', '6111', '5768', '5504', '5741', '5606', '6480', '6167', '6096', '6005', '5522', '5974', '6435', '5643', '6290', '5780', '6444', '6083', '5989', '5893', '5539', '6347', '6016', '6210', '6391', '5789', '5967', '5778', '6035', '6476', '5836', '5702', '6003', '5881', '5714', '6002', '6024', '6203', '6119', '5656', '5691', '5944', '5935', '6046', '5763', '6032', '6266', '6250', '5997', '6207', '6092', '6103', '6043', '5999', '5725', '5552', '6007', '6314', '6159', '5844', '5633', '6269', '5720', '5961', '5583', '6446', '5877', '6171', '6199', '6315', '6271', '5756', '6497', '6383', '5704', '5585', '6144', '6384', '6426', '6285', '5611', '6439', '6351', '5574', '5609', '5905', '5538', '5824', '6149', '6036', '5728', '5515', '5929', '6422', '5644', '6366', '5900', '6354', '6121', '5669', '6394', '5703', '5978', '6022', '6085', '5604', '6436', '5688', '6079', '5767', '6378', '5541', '6398', '6265', '6174', '5809', '5819', '6428', '6163', '5660', '6342', '6097', '6128', '6114', '6183', '5685', '5711', '6277', '6089', '5584', '6201', '6305', '6427', '5975', '5642', '6048', '6091', '6130', '5673', '5621', '5993', '5528', '6353', '6345', '6241', '6041', '6137', '6019', '5810', '6385', '6000', '6169', '6298', '6078', '5699', '6358', '5588', '5546', '5678', '5627', '6106', '5785', '6055', '6425', '5906', '5928', '6415', '6182', '6075', '5962', '6052', '6382', '6145', '6129', '6498', '5904', '5779', '5520', '5784', '5783', '6334', '5970', '6205', '5847', '6441', '6066', '6365', '6176', '5849', '6371', '6326', '5686', '5708', '6180', '5814', '5636', '6431', '6405', '6070', '5869', '6077', '5738', '6080', '6496', '5950', '5806', '5782', '5827', '5896', '5598', '5746', '6014', '5742', '6465', '6123', '5964', '6038', '6218', '6020', '5727', '5888', '5530', '6389', '6061', '6483', '6031', '5901', '6393', '6466', '6320', '5666', '5805', '6168', '5986', '5833', '6143', '6181', '5635', '5681', '6447', '6047', '5570', '5898', '5560', '5931', '6126', '6053', '5823', '5566', '5526', '5858', '5548', '6209', '6336', '6011', '5587', '5677', '6082', '5891', '5839', '5874', '5579', '6214', '6397', '5568', '6263', '5991', '5972', '6081', '6490', '6267', '6310', '6248', '5937', '6216', '6333', '5608', '5875', '5551', '6445', '5983', '5848', '5954', '6262', '5762', '6146', '6191', '6206', '6355', '6244', '5868', '5980', '6423', '5922', '6099', '5933', '5614', '5713', '6317', '6312', '5984', '6255', '6187', '6162', '5930', '5690', '5813', '6192', '6400', '5533', '5973', '6150', '6308', '6313', '6125', '6124', '5733', '5951', '5957', '5662', '5765', '5501', '5894', '5797', '5729', '5730', '6403', '6033', '6455', '5895', '6017', '5712', '6219', '5615', '6208', '6198', '6157', '5634', '6408', '5947', '5745', '5971', '6228', '6296', '5843', '5804', '6293', '6202', '5716', '5846', '6461', '5569', '6006', '5603', '6135', '6360', '5717', '6193', '5792', '5775', '5507', '6243', '5872', '6499', '5736', '6158', '6340', '5995', '6311', '6258', '5938', '6479', '5572', '5882', '6195', '6297', '5943', '5825', '6328', '6330', '5679', '6319', '6236', '6485', '6414', '5908', '6001', '5558', '6396', '6486', '5757', '5803', '5700', '5593', '5866', '6433', '5726', '6240', '5830', '6449', '5575', '6478', '5564', '5915', '6034', '6072', '6484', '6375', '5976', '5631', '6138', '5659', '6346', '6118', '6279', '5554', '6283', '5800', '5594', '5701', '6292', '5842', '5518', '6335', '5750', '6196', '5749', '6329', '6369', '5760', '6134', '5661', '6188', '5542', '6127', '6062', '6352', '6270', '5761', '6165', '6376', '6049', '5687', '6364', '5696', '6367', '5990', '5771', '6057', '6094', '5815', '6039', '5759', '5949', '5563', '5590', '5853', '6009', '5907', '5834', '5982', '5664', '6316', '5557', '6067', '6249', '6142', '6357', '5790', '5647', '5808', '5860', '6012'] + +1000.times do + x = a1 & a2 + y = a2 & a1 +end diff --git a/benchmark/bm_array_join_ary.rb b/benchmark/bm_array_join_ary.rb new file mode 100644 index 00000000..69403de2 --- /dev/null +++ b/benchmark/bm_array_join_ary.rb @@ -0,0 +1,9 @@ +a = [] + +1000.times do |i| + a << [i] +end + +1000.times do + a.join +end diff --git a/benchmark/bm_array_minus_numbers.rb b/benchmark/bm_array_minus_numbers.rb new file mode 100644 index 00000000..03b9256b --- /dev/null +++ b/benchmark/bm_array_minus_numbers.rb @@ -0,0 +1,7 @@ +a1 = [4768, 4964, 4266, 4872, 4231, 4017, 4565, 4793, 4298, 4135, 4639, 4780, 4237, 4548, 4655, 4153, 4654, 4922, 4563, 4042, 4329, 4699, 4352, 4127, 4544, 4906, 4814, 4948, 4977, 4830, 4405, 4642, 4666, 4402, 4679, 4465, 4401, 4155, 4767, 4510, 4747, 4993, 4508, 4697, 4758, 4133, 4348, 4200, 4442, 4970, 4452, 4041, 4103, 4567, 4937, 4047, 4933, 4121, 4860, 4659, 4221, 4312, 4583, 4473, 4973, 4262, 4630, 4123, 4139, 4289, 4147, 4222, 4050, 4019, 4454, 4253, 4552, 4947, 4725, 4457, 4929, 4021, 4502, 4307, 4576, 4124, 4586, 4610, 4027, 4572, 4926, 4753, 4185, 4382, 4394, 4923, 4186, 4254, 4012, 4417, 4556, 4349, 4550, 4330, 4938, 4985, 4778, 4716, 4924, 4045, 4358, 4189, 4591, 4213, 4851, 4825, 4260, 4198, 4342, 4824, 4333, 4244, 4752, 4994, 4488, 4532, 4082, 4595, 4098, 4436, 4540, 4267, 4407, 4998, 4751, 4535, 4861, 4819, 4419, 4031, 4029, 4453, 4698, 4965, 4450, 4668, 4036, 4300, 4519, 4281, 4981, 4818, 4939, 4378, 4140, 4841, 4249, 4290, 4388, 4878, 4884, 4235, 4515, 4638, 4410, 4054, 4383, 4238, 4870, 4295, 4804, 4308, 4614, 4105, 4053, 4446, 4757, 4971, 4637, 4831, 4193, 4912, 4000, 4187, 4606, 4566, 4169, 4641, 4749, 4729, 4928, 4601, 4949, 4210, 4313, 4647, 4495, 4460, 4621, 4605, 4694, 4317, 4226, 4263, 4016, 4997, 4940, 4715, 4907, 4620, 4934, 4996, 4955, 4688, 4304, 4220, 4882, 4772, 4536, 4815, 4693, 4469, 4276, 4409, 4071, 4224, 4020, 4629, 4865, 4813, 4366, 4622, 4129, 4533, 4634, 4564, 4087, 4386, 4161, 4265, 4711, 4009, 4376, 4781, 4837, 4112, 4915, 4592, 4658, 4025, 4987, 4291, 4477, 4503, 4437, 4111, 4707, 4879, 4611, 4549, 4078, 4044, 4853, 4835, 4463, 4577, 4008, 4233, 4741, 4384, 4225, 4024, 4726, 4743, 4160, 4180, 4722, 4609, 4114, 4834, 4742, 4662, 4984, 4299, 4060, 4498, 4755, 4320, 4874, 4528, 4216, 4852, 4951, 4958, 4283, 4239, 4476, 4644, 4143, 4104, 4455, 4126, 4950, 4663, 4013, 4931, 4850, 4242, 4130, 4623, 4871, 4014, 4854, 4293, 4512, 4166, 4740, 4735, 4150, 4651, 4172, 4836, 4530, 4664, 4429, 4511, 4558, 4676, 4085, 4074, 4580, 4794, 4379, 4310, 4817, 4966, 4848, 4202, 4336, 4608, 4351, 4396, 4652, 4033, 4188, 4431, 4916, 4259, 4607, 4816, 4810, 4627, 4527, 4560, 4728, 4589, 4274, 4809, 4790, 4398, 4414, 4516, 4581, 4919, 4665, 4331, 4978, 4543, 4877, 4974, 4284, 4004, 4177, 4466, 4116, 4217, 4901, 4372, 4137, 4806, 4264, 4497, 4294, 4787, 4212, 4215, 4115, 4782, 4739, 4821, 4125, 4505, 4230, 4399, 4395, 4079, 4867, 4381, 4706, 4695, 4404, 4691, 4075, 4353, 4301, 4876, 4731, 4523, 4246, 4529, 4412, 4784, 4449, 4229, 4616, 4158, 4002, 4318, 4377, 4205, 4911, 4777, 4792, 4271, 4763, 4141, 4287, 4890, 4279, 4829, 4646, 4840, 4089, 4880, 4067, 4918, 4059, 4109, 4164, 4863, 4883, 4909, 4361, 4174, 4960, 4302, 4003, 4236, 4846, 4034, 4324, 4513, 4765, 4596, 4900, 4007, 4603, 4474, 4439, 4805, 4015, 4496, 4953, 4363, 4551, 4459, 4063, 4983, 4881, 4365, 4604, 4587, 4798, 4005, 4163, 4421, 4471, 4826, 4144, 4635, 4600, 4913, 4640, 4247, 4766, 4779, 4280, 4391, 4891, 4636, 4546, 4683, 4181, 4081, 4862, 4458, 4037, 4321, 4786, 4717, 4628, 4154, 4326, 4032, 4873, 4151, 4905, 4270, 4156, 4733, 4980, 4866, 4325, 4055, 4467, 4480, 4286, 4191, 4762, 4322, 4574, 4022, 4056, 4770, 4451, 4448, 4845, 4341, 4433, 4245, 4684, 4671, 4093, 4920, 4272, 4745, 4799, 4761, 4250, 4578, 4347, 4499, 4526, 4369, 4162, 4537, 4434, 4893, 4120, 4962, 4667, 4525, 4091, 4462, 4182, 4738, 4935, 4173, 4490, 4571, 4424, 4894, 4051, 4214, 4823, 4096, 4206, 4598, 4943, 4701, 4649, 4807, 4107, 4435, 4456, 4083, 4612, 4721, 4472, 4146, 4925, 4340, 4789, 4277, 4375, 4211, 4427, 4547, 4690, 4613, 4727, 4006, 4203, 4430, 4223, 4039, 4932, 4296, 4108, 4278, 4832, 4422, 4917, 4470, 4183, 4887, 4076, 4485, 4597, 4443, 4257, 4991, 4944, 4196, 4672, 4397, 4097, 4119, 4077, 4773, 4602, 4538, 4479, 4968, 4159, 4539, 4956, 4710, 4812, 4902, 4569, 4954, 4385, 4128, 4936, 4416, 4148, 4632, 4759, 4117, 4896, 4392, 4864, 4316, 4132, 4319, 4969, 4175, 4484, 4903, 4910, 4350, 4332, 4952, 4176, 4594, 4709, 4509, 4178, 4167, 4545, 4857, 4617, 4501, 4859, 4207, 4275, 4687, 4049, 4579, 4046, 4921, 4113, 4898, 4681, 4052, 4415, 4064, 4184, 4895, 4744, 4685, 4084, 4305, 4899, 4559, 4208, 4057, 4507, 4258, 4355, 4086, 4373, 4323, 4541, 4297, 4483, 4889, 4531, 4327, 4441, 4914, 4303, 4677, 4445, 4802, 4343, 4585, 4338, 4524, 4590, 4624, 4288, 4704, 4134, 4043, 4720, 4058, 4328, 4095, 4026, 4423, 4657, 4118, 4633, 4487, 4822, 4904, 4255, 4001, 4387, 4500, 4190, 4686, 4995, 4661, 4783, 4992, 4165, 4065, 4927, 4306, 4856, 4292, 4420, 4963, 4468, 4240, 4724, 4432, 4447, 4518, 4028, 4670, 4339, 4771, 4018, 4489, 4110, 4708, 4945, 4136, 4492, 4930, 4090, 4734, 4886, 4542, 4227, 4486, 4491, 4713, 4986, 4068, 4048, 4975, 4570, 4842, 4475, 4131, 4555, 4428, 4776, 4101, 4273, 4811, 4345, 5000, 4653, 4256, 4209, 4769, 4946, 4561, 4080, 4461, 4820, 4311, 4959, 4750, 4795, 4748, 4368, 4506, 4335, 4346, 4568, 4675, 4692, 4774, 4413, 4370, 4723, 4521, 4885, 4678, 4897, 4066, 4674, 4106, 4626, 4389, 4204, 4839, 4023, 4712, 4145, 4035, 4357, 4756, 4648, 4972, 4157, 4406, 4615, 4061, 4219, 4791, 4660, 4073, 4356, 4072, 4599, 4359, 4094, 4673, 4696, 4796, 4282, 4714, 4522, 4736, 4775, 4760, 4400, 4847, 4228, 4803, 4908, 4732, 4645, 4122, 4218, 4478, 4941, 4892, 4364, 4403, 4152, 4444, 4360, 4354, 4241, 4494, 4367, 4808, 4261, 4088, 4573, 4554, 4248, 4371, 4393, 4268, 4201, 4038, 4788, 4593, 4040, 4801, 4582, 4309, 4976, 4374, 4869, 4380, 4514, 4243, 4362, 4849, 4680, 4888, 4764, 4618, 4838, 4828, 4643, 4010, 4827, 4957, 4099, 4875, 4843, 4737, 4102, 4979, 4011, 4504, 4440, 4746, 4557, 4426, 4553, 4656, 4868, 4689, 4988, 4703, 4967, 4069, 4619, 4334, 4669, 4785, 4464, 4562, 4961, 4625, 4754, 4797, 4481, 4705, 4199, 4337, 4062, 4138, 4702, 4534, 4168, 4418, 4092, 4682, 4520, 4030, 4171, 4650, 4858, 4411, 4999, 4252, 4197, 4170, 4942, 4631, 4990, 4179, 4285, 4700, 4482, 4575, 4800, 4070, 4251, 4344, 4982, 4719, 4390, 4149, 4100, 4194, 4269, 4855, 4314, 4718, 4232, 4730, 4438, 4588, 4195, 4192, 4493, 4517, 4833, 4234, 4989, 4315, 4844, 4142, 4408, 4584, 4425] +a2 = [5650, 6274, 5600, 6197, 6324, 5850, 5630, 5955, 6343, 6233, 6065, 5637, 5561, 6500, 5565, 5845, 5916, 6229, 5857, 5747, 6419, 5936, 6363, 5773, 6399, 6350, 6172, 6494, 6042, 6013, 6132, 5887, 6215, 5837, 5663, 5695, 6453, 5698, 5941, 6186, 5902, 6116, 6487, 5945, 5694, 6392, 5605, 5524, 5884, 6470, 5503, 6458, 5910, 6469, 5645, 5540, 5505, 6136, 5715, 6306, 6164, 6406, 6120, 5919, 5592, 5595, 5684, 6464, 5958, 6060, 5862, 5672, 5670, 6211, 6321, 5654, 5516, 6278, 6084, 5867, 5577, 6379, 6139, 6472, 6251, 6460, 5831, 6133, 5772, 5788, 6260, 5580, 5912, 5865, 5616, 6153, 5567, 5709, 5963, 6489, 6344, 6113, 6409, 5987, 6141, 5508, 6093, 5723, 5883, 5829, 6086, 5774, 6026, 5601, 5859, 5517, 6252, 6412, 6481, 5828, 5556, 6234, 6416, 5562, 5992, 6045, 5559, 6309, 6109, 6273, 6407, 5743, 6338, 5706, 5719, 6430, 5693, 6247, 6450, 5710, 6015, 6429, 5607, 6056, 6495, 5613, 6370, 5671, 5751, 6237, 5748, 6217, 5977, 6194, 5511, 5599, 5624, 5923, 6452, 5841, 5798, 6025, 5879, 6420, 6177, 6294, 5871, 6105, 5822, 5770, 5724, 5754, 6063, 6291, 5529, 5921, 6018, 5856, 6058, 6372, 6361, 5889, 5899, 5555, 6454, 5960, 6411, 5512, 6069, 5913, 5502, 5821, 5965, 6475, 5697, 5523, 5676, 6076, 5648, 5769, 5948, 6493, 5683, 6200, 5651, 5653, 5885, 5667, 6404, 6432, 6226, 6102, 6213, 5796, 6462, 5811, 5764, 6100, 6073, 6117, 6147, 6373, 5777, 6221, 6184, 5553, 5731, 5536, 6288, 6204, 5586, 5707, 5753, 6362, 5602, 5924, 6231, 5832, 6264, 5968, 5597, 6467, 5946, 6212, 6275, 5509, 6156, 5582, 5816, 5909, 5791, 5952, 6442, 6474, 6023, 5939, 5649, 5531, 6259, 5994, 6388, 5776, 5641, 6068, 6477, 6220, 6286, 5897, 5873, 6381, 6339, 5652, 5589, 6302, 6227, 5544, 5793, 5892, 6488, 5506, 5876, 5781, 5576, 5521, 6331, 6131, 5617, 6332, 5801, 6107, 6463, 6457, 5802, 5737, 6104, 5550, 6253, 6368, 6050, 5766, 5534, 6224, 6401, 6303, 5786, 5735, 6282, 5596, 6459, 6122, 6492, 5854, 5988, 5549, 6318, 5840, 6178, 5640, 5752, 6040, 5665, 5755, 5535, 5721, 6088, 5914, 5689, 6256, 5838, 6021, 5674, 6028, 6223, 6189, 5886, 6232, 5878, 6424, 6413, 6482, 6155, 5638, 6160, 6440, 5571, 6037, 6323, 5959, 6468, 5826, 5682, 6327, 5514, 6390, 5510, 5870, 6108, 5722, 5934, 5998, 6402, 6348, 5718, 6471, 5942, 6029, 6185, 5926, 6386, 5940, 6443, 6230, 5855, 6349, 6059, 6276, 5740, 5996, 6238, 6287, 5812, 5578, 5658, 5525, 6380, 6095, 6112, 5925, 6246, 5985, 5692, 6261, 5734, 6337, 5966, 6004, 6151, 6161, 5917, 5863, 6300, 5732, 5547, 5851, 6295, 5787, 5864, 5545, 6356, 6175, 6154, 5680, 5799, 5500, 5969, 6301, 5622, 6071, 6030, 5655, 6299, 5519, 5818, 6064, 6054, 5646, 6166, 6272, 5610, 5705, 5956, 5820, 5920, 5581, 6268, 6027, 6074, 6087, 5668, 5794, 5880, 6173, 6434, 6374, 6008, 5807, 5739, 6307, 6437, 5619, 6451, 5618, 5628, 5932, 6235, 6190, 6225, 5629, 5911, 6257, 6410, 6304, 6140, 6395, 5817, 6284, 5927, 6010, 5639, 5758, 6098, 6051, 6239, 5979, 6281, 6417, 5903, 5675, 6456, 5795, 5527, 6242, 6387, 6090, 5623, 5890, 6322, 6418, 6110, 6254, 5620, 5537, 5573, 6359, 5612, 6325, 5513, 6044, 5918, 6473, 6148, 6341, 5543, 6448, 6101, 6280, 6222, 6438, 5981, 6152, 5532, 5626, 6491, 5591, 6170, 5953, 6115, 5744, 6179, 5632, 5861, 6421, 6377, 6245, 5852, 5835, 5625, 6289, 5657, 6111, 5768, 5504, 5741, 5606, 6480, 6167, 6096, 6005, 5522, 5974, 6435, 5643, 6290, 5780, 6444, 6083, 5989, 5893, 5539, 6347, 6016, 6210, 6391, 5789, 5967, 5778, 6035, 6476, 5836, 5702, 6003, 5881, 5714, 6002, 6024, 6203, 6119, 5656, 5691, 5944, 5935, 6046, 5763, 6032, 6266, 6250, 5997, 6207, 6092, 6103, 6043, 5999, 5725, 5552, 6007, 6314, 6159, 5844, 5633, 6269, 5720, 5961, 5583, 6446, 5877, 6171, 6199, 6315, 6271, 5756, 6497, 6383, 5704, 5585, 6144, 6384, 6426, 6285, 5611, 6439, 6351, 5574, 5609, 5905, 5538, 5824, 6149, 6036, 5728, 5515, 5929, 6422, 5644, 6366, 5900, 6354, 6121, 5669, 6394, 5703, 5978, 6022, 6085, 5604, 6436, 5688, 6079, 5767, 6378, 5541, 6398, 6265, 6174, 5809, 5819, 6428, 6163, 5660, 6342, 6097, 6128, 6114, 6183, 5685, 5711, 6277, 6089, 5584, 6201, 6305, 6427, 5975, 5642, 6048, 6091, 6130, 5673, 5621, 5993, 5528, 6353, 6345, 6241, 6041, 6137, 6019, 5810, 6385, 6000, 6169, 6298, 6078, 5699, 6358, 5588, 5546, 5678, 5627, 6106, 5785, 6055, 6425, 5906, 5928, 6415, 6182, 6075, 5962, 6052, 6382, 6145, 6129, 6498, 5904, 5779, 5520, 5784, 5783, 6334, 5970, 6205, 5847, 6441, 6066, 6365, 6176, 5849, 6371, 6326, 5686, 5708, 6180, 5814, 5636, 6431, 6405, 6070, 5869, 6077, 5738, 6080, 6496, 5950, 5806, 5782, 5827, 5896, 5598, 5746, 6014, 5742, 6465, 6123, 5964, 6038, 6218, 6020, 5727, 5888, 5530, 6389, 6061, 6483, 6031, 5901, 6393, 6466, 6320, 5666, 5805, 6168, 5986, 5833, 6143, 6181, 5635, 5681, 6447, 6047, 5570, 5898, 5560, 5931, 6126, 6053, 5823, 5566, 5526, 5858, 5548, 6209, 6336, 6011, 5587, 5677, 6082, 5891, 5839, 5874, 5579, 6214, 6397, 5568, 6263, 5991, 5972, 6081, 6490, 6267, 6310, 6248, 5937, 6216, 6333, 5608, 5875, 5551, 6445, 5983, 5848, 5954, 6262, 5762, 6146, 6191, 6206, 6355, 6244, 5868, 5980, 6423, 5922, 6099, 5933, 5614, 5713, 6317, 6312, 5984, 6255, 6187, 6162, 5930, 5690, 5813, 6192, 6400, 5533, 5973, 6150, 6308, 6313, 6125, 6124, 5733, 5951, 5957, 5662, 5765, 5501, 5894, 5797, 5729, 5730, 6403, 6033, 6455, 5895, 6017, 5712, 6219, 5615, 6208, 6198, 6157, 5634, 6408, 5947, 5745, 5971, 6228, 6296, 5843, 5804, 6293, 6202, 5716, 5846, 6461, 5569, 6006, 5603, 6135, 6360, 5717, 6193, 5792, 5775, 5507, 6243, 5872, 6499, 5736, 6158, 6340, 5995, 6311, 6258, 5938, 6479, 5572, 5882, 6195, 6297, 5943, 5825, 6328, 6330, 5679, 6319, 6236, 6485, 6414, 5908, 6001, 5558, 6396, 6486, 5757, 5803, 5700, 5593, 5866, 6433, 5726, 6240, 5830, 6449, 5575, 6478, 5564, 5915, 6034, 6072, 6484, 6375, 5976, 5631, 6138, 5659, 6346, 6118, 6279, 5554, 6283, 5800, 5594, 5701, 6292, 5842, 5518, 6335, 5750, 6196, 5749, 6329, 6369, 5760, 6134, 5661, 6188, 5542, 6127, 6062, 6352, 6270, 5761, 6165, 6376, 6049, 5687, 6364, 5696, 6367, 5990, 5771, 6057, 6094, 5815, 6039, 5759, 5949, 5563, 5590, 5853, 6009, 5907, 5834, 5982, 5664, 6316, 5557, 6067, 6249, 6142, 6357, 5790, 5647, 5808, 5860, 6012] + +1000.times do + x = a1 - a2 + y = a2 - a1 +end diff --git a/benchmark/bm_array_minus_objects.rb b/benchmark/bm_array_minus_objects.rb new file mode 100644 index 00000000..2ac89b30 --- /dev/null +++ b/benchmark/bm_array_minus_objects.rb @@ -0,0 +1,7 @@ +a1 = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] +a2 = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] + +1000.times do + x = a1 - a2 + y = a2 - a1 +end diff --git a/benchmark/bm_array_minus_strings.rb b/benchmark/bm_array_minus_strings.rb new file mode 100644 index 00000000..308ec381 --- /dev/null +++ b/benchmark/bm_array_minus_strings.rb @@ -0,0 +1,7 @@ +a1 = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] +a2 = ['5650', '6274', '5600', '6197', '6324', '5850', '5630', '5955', '6343', '6233', '6065', '5637', '5561', '6500', '5565', '5845', '5916', '6229', '5857', '5747', '6419', '5936', '6363', '5773', '6399', '6350', '6172', '6494', '6042', '6013', '6132', '5887', '6215', '5837', '5663', '5695', '6453', '5698', '5941', '6186', '5902', '6116', '6487', '5945', '5694', '6392', '5605', '5524', '5884', '6470', '5503', '6458', '5910', '6469', '5645', '5540', '5505', '6136', '5715', '6306', '6164', '6406', '6120', '5919', '5592', '5595', '5684', '6464', '5958', '6060', '5862', '5672', '5670', '6211', '6321', '5654', '5516', '6278', '6084', '5867', '5577', '6379', '6139', '6472', '6251', '6460', '5831', '6133', '5772', '5788', '6260', '5580', '5912', '5865', '5616', '6153', '5567', '5709', '5963', '6489', '6344', '6113', '6409', '5987', '6141', '5508', '6093', '5723', '5883', '5829', '6086', '5774', '6026', '5601', '5859', '5517', '6252', '6412', '6481', '5828', '5556', '6234', '6416', '5562', '5992', '6045', '5559', '6309', '6109', '6273', '6407', '5743', '6338', '5706', '5719', '6430', '5693', '6247', '6450', '5710', '6015', '6429', '5607', '6056', '6495', '5613', '6370', '5671', '5751', '6237', '5748', '6217', '5977', '6194', '5511', '5599', '5624', '5923', '6452', '5841', '5798', '6025', '5879', '6420', '6177', '6294', '5871', '6105', '5822', '5770', '5724', '5754', '6063', '6291', '5529', '5921', '6018', '5856', '6058', '6372', '6361', '5889', '5899', '5555', '6454', '5960', '6411', '5512', '6069', '5913', '5502', '5821', '5965', '6475', '5697', '5523', '5676', '6076', '5648', '5769', '5948', '6493', '5683', '6200', '5651', '5653', '5885', '5667', '6404', '6432', '6226', '6102', '6213', '5796', '6462', '5811', '5764', '6100', '6073', '6117', '6147', '6373', '5777', '6221', '6184', '5553', '5731', '5536', '6288', '6204', '5586', '5707', '5753', '6362', '5602', '5924', '6231', '5832', '6264', '5968', '5597', '6467', '5946', '6212', '6275', '5509', '6156', '5582', '5816', '5909', '5791', '5952', '6442', '6474', '6023', '5939', '5649', '5531', '6259', '5994', '6388', '5776', '5641', '6068', '6477', '6220', '6286', '5897', '5873', '6381', '6339', '5652', '5589', '6302', '6227', '5544', '5793', '5892', '6488', '5506', '5876', '5781', '5576', '5521', '6331', '6131', '5617', '6332', '5801', '6107', '6463', '6457', '5802', '5737', '6104', '5550', '6253', '6368', '6050', '5766', '5534', '6224', '6401', '6303', '5786', '5735', '6282', '5596', '6459', '6122', '6492', '5854', '5988', '5549', '6318', '5840', '6178', '5640', '5752', '6040', '5665', '5755', '5535', '5721', '6088', '5914', '5689', '6256', '5838', '6021', '5674', '6028', '6223', '6189', '5886', '6232', '5878', '6424', '6413', '6482', '6155', '5638', '6160', '6440', '5571', '6037', '6323', '5959', '6468', '5826', '5682', '6327', '5514', '6390', '5510', '5870', '6108', '5722', '5934', '5998', '6402', '6348', '5718', '6471', '5942', '6029', '6185', '5926', '6386', '5940', '6443', '6230', '5855', '6349', '6059', '6276', '5740', '5996', '6238', '6287', '5812', '5578', '5658', '5525', '6380', '6095', '6112', '5925', '6246', '5985', '5692', '6261', '5734', '6337', '5966', '6004', '6151', '6161', '5917', '5863', '6300', '5732', '5547', '5851', '6295', '5787', '5864', '5545', '6356', '6175', '6154', '5680', '5799', '5500', '5969', '6301', '5622', '6071', '6030', '5655', '6299', '5519', '5818', '6064', '6054', '5646', '6166', '6272', '5610', '5705', '5956', '5820', '5920', '5581', '6268', '6027', '6074', '6087', '5668', '5794', '5880', '6173', '6434', '6374', '6008', '5807', '5739', '6307', '6437', '5619', '6451', '5618', '5628', '5932', '6235', '6190', '6225', '5629', '5911', '6257', '6410', '6304', '6140', '6395', '5817', '6284', '5927', '6010', '5639', '5758', '6098', '6051', '6239', '5979', '6281', '6417', '5903', '5675', '6456', '5795', '5527', '6242', '6387', '6090', '5623', '5890', '6322', '6418', '6110', '6254', '5620', '5537', '5573', '6359', '5612', '6325', '5513', '6044', '5918', '6473', '6148', '6341', '5543', '6448', '6101', '6280', '6222', '6438', '5981', '6152', '5532', '5626', '6491', '5591', '6170', '5953', '6115', '5744', '6179', '5632', '5861', '6421', '6377', '6245', '5852', '5835', '5625', '6289', '5657', '6111', '5768', '5504', '5741', '5606', '6480', '6167', '6096', '6005', '5522', '5974', '6435', '5643', '6290', '5780', '6444', '6083', '5989', '5893', '5539', '6347', '6016', '6210', '6391', '5789', '5967', '5778', '6035', '6476', '5836', '5702', '6003', '5881', '5714', '6002', '6024', '6203', '6119', '5656', '5691', '5944', '5935', '6046', '5763', '6032', '6266', '6250', '5997', '6207', '6092', '6103', '6043', '5999', '5725', '5552', '6007', '6314', '6159', '5844', '5633', '6269', '5720', '5961', '5583', '6446', '5877', '6171', '6199', '6315', '6271', '5756', '6497', '6383', '5704', '5585', '6144', '6384', '6426', '6285', '5611', '6439', '6351', '5574', '5609', '5905', '5538', '5824', '6149', '6036', '5728', '5515', '5929', '6422', '5644', '6366', '5900', '6354', '6121', '5669', '6394', '5703', '5978', '6022', '6085', '5604', '6436', '5688', '6079', '5767', '6378', '5541', '6398', '6265', '6174', '5809', '5819', '6428', '6163', '5660', '6342', '6097', '6128', '6114', '6183', '5685', '5711', '6277', '6089', '5584', '6201', '6305', '6427', '5975', '5642', '6048', '6091', '6130', '5673', '5621', '5993', '5528', '6353', '6345', '6241', '6041', '6137', '6019', '5810', '6385', '6000', '6169', '6298', '6078', '5699', '6358', '5588', '5546', '5678', '5627', '6106', '5785', '6055', '6425', '5906', '5928', '6415', '6182', '6075', '5962', '6052', '6382', '6145', '6129', '6498', '5904', '5779', '5520', '5784', '5783', '6334', '5970', '6205', '5847', '6441', '6066', '6365', '6176', '5849', '6371', '6326', '5686', '5708', '6180', '5814', '5636', '6431', '6405', '6070', '5869', '6077', '5738', '6080', '6496', '5950', '5806', '5782', '5827', '5896', '5598', '5746', '6014', '5742', '6465', '6123', '5964', '6038', '6218', '6020', '5727', '5888', '5530', '6389', '6061', '6483', '6031', '5901', '6393', '6466', '6320', '5666', '5805', '6168', '5986', '5833', '6143', '6181', '5635', '5681', '6447', '6047', '5570', '5898', '5560', '5931', '6126', '6053', '5823', '5566', '5526', '5858', '5548', '6209', '6336', '6011', '5587', '5677', '6082', '5891', '5839', '5874', '5579', '6214', '6397', '5568', '6263', '5991', '5972', '6081', '6490', '6267', '6310', '6248', '5937', '6216', '6333', '5608', '5875', '5551', '6445', '5983', '5848', '5954', '6262', '5762', '6146', '6191', '6206', '6355', '6244', '5868', '5980', '6423', '5922', '6099', '5933', '5614', '5713', '6317', '6312', '5984', '6255', '6187', '6162', '5930', '5690', '5813', '6192', '6400', '5533', '5973', '6150', '6308', '6313', '6125', '6124', '5733', '5951', '5957', '5662', '5765', '5501', '5894', '5797', '5729', '5730', '6403', '6033', '6455', '5895', '6017', '5712', '6219', '5615', '6208', '6198', '6157', '5634', '6408', '5947', '5745', '5971', '6228', '6296', '5843', '5804', '6293', '6202', '5716', '5846', '6461', '5569', '6006', '5603', '6135', '6360', '5717', '6193', '5792', '5775', '5507', '6243', '5872', '6499', '5736', '6158', '6340', '5995', '6311', '6258', '5938', '6479', '5572', '5882', '6195', '6297', '5943', '5825', '6328', '6330', '5679', '6319', '6236', '6485', '6414', '5908', '6001', '5558', '6396', '6486', '5757', '5803', '5700', '5593', '5866', '6433', '5726', '6240', '5830', '6449', '5575', '6478', '5564', '5915', '6034', '6072', '6484', '6375', '5976', '5631', '6138', '5659', '6346', '6118', '6279', '5554', '6283', '5800', '5594', '5701', '6292', '5842', '5518', '6335', '5750', '6196', '5749', '6329', '6369', '5760', '6134', '5661', '6188', '5542', '6127', '6062', '6352', '6270', '5761', '6165', '6376', '6049', '5687', '6364', '5696', '6367', '5990', '5771', '6057', '6094', '5815', '6039', '5759', '5949', '5563', '5590', '5853', '6009', '5907', '5834', '5982', '5664', '6316', '5557', '6067', '6249', '6142', '6357', '5790', '5647', '5808', '5860', '6012'] + +1000.times do + x = a1 - a2 + y = a2 - a1 +end diff --git a/benchmark/bm_array_union_numbers.rb b/benchmark/bm_array_union_numbers.rb new file mode 100644 index 00000000..87907624 --- /dev/null +++ b/benchmark/bm_array_union_numbers.rb @@ -0,0 +1,7 @@ +a1 = [4768, 4964, 4266, 4872, 4231, 4017, 4565, 4793, 4298, 4135, 4639, 4780, 4237, 4548, 4655, 4153, 4654, 4922, 4563, 4042, 4329, 4699, 4352, 4127, 4544, 4906, 4814, 4948, 4977, 4830, 4405, 4642, 4666, 4402, 4679, 4465, 4401, 4155, 4767, 4510, 4747, 4993, 4508, 4697, 4758, 4133, 4348, 4200, 4442, 4970, 4452, 4041, 4103, 4567, 4937, 4047, 4933, 4121, 4860, 4659, 4221, 4312, 4583, 4473, 4973, 4262, 4630, 4123, 4139, 4289, 4147, 4222, 4050, 4019, 4454, 4253, 4552, 4947, 4725, 4457, 4929, 4021, 4502, 4307, 4576, 4124, 4586, 4610, 4027, 4572, 4926, 4753, 4185, 4382, 4394, 4923, 4186, 4254, 4012, 4417, 4556, 4349, 4550, 4330, 4938, 4985, 4778, 4716, 4924, 4045, 4358, 4189, 4591, 4213, 4851, 4825, 4260, 4198, 4342, 4824, 4333, 4244, 4752, 4994, 4488, 4532, 4082, 4595, 4098, 4436, 4540, 4267, 4407, 4998, 4751, 4535, 4861, 4819, 4419, 4031, 4029, 4453, 4698, 4965, 4450, 4668, 4036, 4300, 4519, 4281, 4981, 4818, 4939, 4378, 4140, 4841, 4249, 4290, 4388, 4878, 4884, 4235, 4515, 4638, 4410, 4054, 4383, 4238, 4870, 4295, 4804, 4308, 4614, 4105, 4053, 4446, 4757, 4971, 4637, 4831, 4193, 4912, 4000, 4187, 4606, 4566, 4169, 4641, 4749, 4729, 4928, 4601, 4949, 4210, 4313, 4647, 4495, 4460, 4621, 4605, 4694, 4317, 4226, 4263, 4016, 4997, 4940, 4715, 4907, 4620, 4934, 4996, 4955, 4688, 4304, 4220, 4882, 4772, 4536, 4815, 4693, 4469, 4276, 4409, 4071, 4224, 4020, 4629, 4865, 4813, 4366, 4622, 4129, 4533, 4634, 4564, 4087, 4386, 4161, 4265, 4711, 4009, 4376, 4781, 4837, 4112, 4915, 4592, 4658, 4025, 4987, 4291, 4477, 4503, 4437, 4111, 4707, 4879, 4611, 4549, 4078, 4044, 4853, 4835, 4463, 4577, 4008, 4233, 4741, 4384, 4225, 4024, 4726, 4743, 4160, 4180, 4722, 4609, 4114, 4834, 4742, 4662, 4984, 4299, 4060, 4498, 4755, 4320, 4874, 4528, 4216, 4852, 4951, 4958, 4283, 4239, 4476, 4644, 4143, 4104, 4455, 4126, 4950, 4663, 4013, 4931, 4850, 4242, 4130, 4623, 4871, 4014, 4854, 4293, 4512, 4166, 4740, 4735, 4150, 4651, 4172, 4836, 4530, 4664, 4429, 4511, 4558, 4676, 4085, 4074, 4580, 4794, 4379, 4310, 4817, 4966, 4848, 4202, 4336, 4608, 4351, 4396, 4652, 4033, 4188, 4431, 4916, 4259, 4607, 4816, 4810, 4627, 4527, 4560, 4728, 4589, 4274, 4809, 4790, 4398, 4414, 4516, 4581, 4919, 4665, 4331, 4978, 4543, 4877, 4974, 4284, 4004, 4177, 4466, 4116, 4217, 4901, 4372, 4137, 4806, 4264, 4497, 4294, 4787, 4212, 4215, 4115, 4782, 4739, 4821, 4125, 4505, 4230, 4399, 4395, 4079, 4867, 4381, 4706, 4695, 4404, 4691, 4075, 4353, 4301, 4876, 4731, 4523, 4246, 4529, 4412, 4784, 4449, 4229, 4616, 4158, 4002, 4318, 4377, 4205, 4911, 4777, 4792, 4271, 4763, 4141, 4287, 4890, 4279, 4829, 4646, 4840, 4089, 4880, 4067, 4918, 4059, 4109, 4164, 4863, 4883, 4909, 4361, 4174, 4960, 4302, 4003, 4236, 4846, 4034, 4324, 4513, 4765, 4596, 4900, 4007, 4603, 4474, 4439, 4805, 4015, 4496, 4953, 4363, 4551, 4459, 4063, 4983, 4881, 4365, 4604, 4587, 4798, 4005, 4163, 4421, 4471, 4826, 4144, 4635, 4600, 4913, 4640, 4247, 4766, 4779, 4280, 4391, 4891, 4636, 4546, 4683, 4181, 4081, 4862, 4458, 4037, 4321, 4786, 4717, 4628, 4154, 4326, 4032, 4873, 4151, 4905, 4270, 4156, 4733, 4980, 4866, 4325, 4055, 4467, 4480, 4286, 4191, 4762, 4322, 4574, 4022, 4056, 4770, 4451, 4448, 4845, 4341, 4433, 4245, 4684, 4671, 4093, 4920, 4272, 4745, 4799, 4761, 4250, 4578, 4347, 4499, 4526, 4369, 4162, 4537, 4434, 4893, 4120, 4962, 4667, 4525, 4091, 4462, 4182, 4738, 4935, 4173, 4490, 4571, 4424, 4894, 4051, 4214, 4823, 4096, 4206, 4598, 4943, 4701, 4649, 4807, 4107, 4435, 4456, 4083, 4612, 4721, 4472, 4146, 4925, 4340, 4789, 4277, 4375, 4211, 4427, 4547, 4690, 4613, 4727, 4006, 4203, 4430, 4223, 4039, 4932, 4296, 4108, 4278, 4832, 4422, 4917, 4470, 4183, 4887, 4076, 4485, 4597, 4443, 4257, 4991, 4944, 4196, 4672, 4397, 4097, 4119, 4077, 4773, 4602, 4538, 4479, 4968, 4159, 4539, 4956, 4710, 4812, 4902, 4569, 4954, 4385, 4128, 4936, 4416, 4148, 4632, 4759, 4117, 4896, 4392, 4864, 4316, 4132, 4319, 4969, 4175, 4484, 4903, 4910, 4350, 4332, 4952, 4176, 4594, 4709, 4509, 4178, 4167, 4545, 4857, 4617, 4501, 4859, 4207, 4275, 4687, 4049, 4579, 4046, 4921, 4113, 4898, 4681, 4052, 4415, 4064, 4184, 4895, 4744, 4685, 4084, 4305, 4899, 4559, 4208, 4057, 4507, 4258, 4355, 4086, 4373, 4323, 4541, 4297, 4483, 4889, 4531, 4327, 4441, 4914, 4303, 4677, 4445, 4802, 4343, 4585, 4338, 4524, 4590, 4624, 4288, 4704, 4134, 4043, 4720, 4058, 4328, 4095, 4026, 4423, 4657, 4118, 4633, 4487, 4822, 4904, 4255, 4001, 4387, 4500, 4190, 4686, 4995, 4661, 4783, 4992, 4165, 4065, 4927, 4306, 4856, 4292, 4420, 4963, 4468, 4240, 4724, 4432, 4447, 4518, 4028, 4670, 4339, 4771, 4018, 4489, 4110, 4708, 4945, 4136, 4492, 4930, 4090, 4734, 4886, 4542, 4227, 4486, 4491, 4713, 4986, 4068, 4048, 4975, 4570, 4842, 4475, 4131, 4555, 4428, 4776, 4101, 4273, 4811, 4345, 5000, 4653, 4256, 4209, 4769, 4946, 4561, 4080, 4461, 4820, 4311, 4959, 4750, 4795, 4748, 4368, 4506, 4335, 4346, 4568, 4675, 4692, 4774, 4413, 4370, 4723, 4521, 4885, 4678, 4897, 4066, 4674, 4106, 4626, 4389, 4204, 4839, 4023, 4712, 4145, 4035, 4357, 4756, 4648, 4972, 4157, 4406, 4615, 4061, 4219, 4791, 4660, 4073, 4356, 4072, 4599, 4359, 4094, 4673, 4696, 4796, 4282, 4714, 4522, 4736, 4775, 4760, 4400, 4847, 4228, 4803, 4908, 4732, 4645, 4122, 4218, 4478, 4941, 4892, 4364, 4403, 4152, 4444, 4360, 4354, 4241, 4494, 4367, 4808, 4261, 4088, 4573, 4554, 4248, 4371, 4393, 4268, 4201, 4038, 4788, 4593, 4040, 4801, 4582, 4309, 4976, 4374, 4869, 4380, 4514, 4243, 4362, 4849, 4680, 4888, 4764, 4618, 4838, 4828, 4643, 4010, 4827, 4957, 4099, 4875, 4843, 4737, 4102, 4979, 4011, 4504, 4440, 4746, 4557, 4426, 4553, 4656, 4868, 4689, 4988, 4703, 4967, 4069, 4619, 4334, 4669, 4785, 4464, 4562, 4961, 4625, 4754, 4797, 4481, 4705, 4199, 4337, 4062, 4138, 4702, 4534, 4168, 4418, 4092, 4682, 4520, 4030, 4171, 4650, 4858, 4411, 4999, 4252, 4197, 4170, 4942, 4631, 4990, 4179, 4285, 4700, 4482, 4575, 4800, 4070, 4251, 4344, 4982, 4719, 4390, 4149, 4100, 4194, 4269, 4855, 4314, 4718, 4232, 4730, 4438, 4588, 4195, 4192, 4493, 4517, 4833, 4234, 4989, 4315, 4844, 4142, 4408, 4584, 4425] +a2 = [5650, 6274, 5600, 6197, 6324, 5850, 5630, 5955, 6343, 6233, 6065, 5637, 5561, 6500, 5565, 5845, 5916, 6229, 5857, 5747, 6419, 5936, 6363, 5773, 6399, 6350, 6172, 6494, 6042, 6013, 6132, 5887, 6215, 5837, 5663, 5695, 6453, 5698, 5941, 6186, 5902, 6116, 6487, 5945, 5694, 6392, 5605, 5524, 5884, 6470, 5503, 6458, 5910, 6469, 5645, 5540, 5505, 6136, 5715, 6306, 6164, 6406, 6120, 5919, 5592, 5595, 5684, 6464, 5958, 6060, 5862, 5672, 5670, 6211, 6321, 5654, 5516, 6278, 6084, 5867, 5577, 6379, 6139, 6472, 6251, 6460, 5831, 6133, 5772, 5788, 6260, 5580, 5912, 5865, 5616, 6153, 5567, 5709, 5963, 6489, 6344, 6113, 6409, 5987, 6141, 5508, 6093, 5723, 5883, 5829, 6086, 5774, 6026, 5601, 5859, 5517, 6252, 6412, 6481, 5828, 5556, 6234, 6416, 5562, 5992, 6045, 5559, 6309, 6109, 6273, 6407, 5743, 6338, 5706, 5719, 6430, 5693, 6247, 6450, 5710, 6015, 6429, 5607, 6056, 6495, 5613, 6370, 5671, 5751, 6237, 5748, 6217, 5977, 6194, 5511, 5599, 5624, 5923, 6452, 5841, 5798, 6025, 5879, 6420, 6177, 6294, 5871, 6105, 5822, 5770, 5724, 5754, 6063, 6291, 5529, 5921, 6018, 5856, 6058, 6372, 6361, 5889, 5899, 5555, 6454, 5960, 6411, 5512, 6069, 5913, 5502, 5821, 5965, 6475, 5697, 5523, 5676, 6076, 5648, 5769, 5948, 6493, 5683, 6200, 5651, 5653, 5885, 5667, 6404, 6432, 6226, 6102, 6213, 5796, 6462, 5811, 5764, 6100, 6073, 6117, 6147, 6373, 5777, 6221, 6184, 5553, 5731, 5536, 6288, 6204, 5586, 5707, 5753, 6362, 5602, 5924, 6231, 5832, 6264, 5968, 5597, 6467, 5946, 6212, 6275, 5509, 6156, 5582, 5816, 5909, 5791, 5952, 6442, 6474, 6023, 5939, 5649, 5531, 6259, 5994, 6388, 5776, 5641, 6068, 6477, 6220, 6286, 5897, 5873, 6381, 6339, 5652, 5589, 6302, 6227, 5544, 5793, 5892, 6488, 5506, 5876, 5781, 5576, 5521, 6331, 6131, 5617, 6332, 5801, 6107, 6463, 6457, 5802, 5737, 6104, 5550, 6253, 6368, 6050, 5766, 5534, 6224, 6401, 6303, 5786, 5735, 6282, 5596, 6459, 6122, 6492, 5854, 5988, 5549, 6318, 5840, 6178, 5640, 5752, 6040, 5665, 5755, 5535, 5721, 6088, 5914, 5689, 6256, 5838, 6021, 5674, 6028, 6223, 6189, 5886, 6232, 5878, 6424, 6413, 6482, 6155, 5638, 6160, 6440, 5571, 6037, 6323, 5959, 6468, 5826, 5682, 6327, 5514, 6390, 5510, 5870, 6108, 5722, 5934, 5998, 6402, 6348, 5718, 6471, 5942, 6029, 6185, 5926, 6386, 5940, 6443, 6230, 5855, 6349, 6059, 6276, 5740, 5996, 6238, 6287, 5812, 5578, 5658, 5525, 6380, 6095, 6112, 5925, 6246, 5985, 5692, 6261, 5734, 6337, 5966, 6004, 6151, 6161, 5917, 5863, 6300, 5732, 5547, 5851, 6295, 5787, 5864, 5545, 6356, 6175, 6154, 5680, 5799, 5500, 5969, 6301, 5622, 6071, 6030, 5655, 6299, 5519, 5818, 6064, 6054, 5646, 6166, 6272, 5610, 5705, 5956, 5820, 5920, 5581, 6268, 6027, 6074, 6087, 5668, 5794, 5880, 6173, 6434, 6374, 6008, 5807, 5739, 6307, 6437, 5619, 6451, 5618, 5628, 5932, 6235, 6190, 6225, 5629, 5911, 6257, 6410, 6304, 6140, 6395, 5817, 6284, 5927, 6010, 5639, 5758, 6098, 6051, 6239, 5979, 6281, 6417, 5903, 5675, 6456, 5795, 5527, 6242, 6387, 6090, 5623, 5890, 6322, 6418, 6110, 6254, 5620, 5537, 5573, 6359, 5612, 6325, 5513, 6044, 5918, 6473, 6148, 6341, 5543, 6448, 6101, 6280, 6222, 6438, 5981, 6152, 5532, 5626, 6491, 5591, 6170, 5953, 6115, 5744, 6179, 5632, 5861, 6421, 6377, 6245, 5852, 5835, 5625, 6289, 5657, 6111, 5768, 5504, 5741, 5606, 6480, 6167, 6096, 6005, 5522, 5974, 6435, 5643, 6290, 5780, 6444, 6083, 5989, 5893, 5539, 6347, 6016, 6210, 6391, 5789, 5967, 5778, 6035, 6476, 5836, 5702, 6003, 5881, 5714, 6002, 6024, 6203, 6119, 5656, 5691, 5944, 5935, 6046, 5763, 6032, 6266, 6250, 5997, 6207, 6092, 6103, 6043, 5999, 5725, 5552, 6007, 6314, 6159, 5844, 5633, 6269, 5720, 5961, 5583, 6446, 5877, 6171, 6199, 6315, 6271, 5756, 6497, 6383, 5704, 5585, 6144, 6384, 6426, 6285, 5611, 6439, 6351, 5574, 5609, 5905, 5538, 5824, 6149, 6036, 5728, 5515, 5929, 6422, 5644, 6366, 5900, 6354, 6121, 5669, 6394, 5703, 5978, 6022, 6085, 5604, 6436, 5688, 6079, 5767, 6378, 5541, 6398, 6265, 6174, 5809, 5819, 6428, 6163, 5660, 6342, 6097, 6128, 6114, 6183, 5685, 5711, 6277, 6089, 5584, 6201, 6305, 6427, 5975, 5642, 6048, 6091, 6130, 5673, 5621, 5993, 5528, 6353, 6345, 6241, 6041, 6137, 6019, 5810, 6385, 6000, 6169, 6298, 6078, 5699, 6358, 5588, 5546, 5678, 5627, 6106, 5785, 6055, 6425, 5906, 5928, 6415, 6182, 6075, 5962, 6052, 6382, 6145, 6129, 6498, 5904, 5779, 5520, 5784, 5783, 6334, 5970, 6205, 5847, 6441, 6066, 6365, 6176, 5849, 6371, 6326, 5686, 5708, 6180, 5814, 5636, 6431, 6405, 6070, 5869, 6077, 5738, 6080, 6496, 5950, 5806, 5782, 5827, 5896, 5598, 5746, 6014, 5742, 6465, 6123, 5964, 6038, 6218, 6020, 5727, 5888, 5530, 6389, 6061, 6483, 6031, 5901, 6393, 6466, 6320, 5666, 5805, 6168, 5986, 5833, 6143, 6181, 5635, 5681, 6447, 6047, 5570, 5898, 5560, 5931, 6126, 6053, 5823, 5566, 5526, 5858, 5548, 6209, 6336, 6011, 5587, 5677, 6082, 5891, 5839, 5874, 5579, 6214, 6397, 5568, 6263, 5991, 5972, 6081, 6490, 6267, 6310, 6248, 5937, 6216, 6333, 5608, 5875, 5551, 6445, 5983, 5848, 5954, 6262, 5762, 6146, 6191, 6206, 6355, 6244, 5868, 5980, 6423, 5922, 6099, 5933, 5614, 5713, 6317, 6312, 5984, 6255, 6187, 6162, 5930, 5690, 5813, 6192, 6400, 5533, 5973, 6150, 6308, 6313, 6125, 6124, 5733, 5951, 5957, 5662, 5765, 5501, 5894, 5797, 5729, 5730, 6403, 6033, 6455, 5895, 6017, 5712, 6219, 5615, 6208, 6198, 6157, 5634, 6408, 5947, 5745, 5971, 6228, 6296, 5843, 5804, 6293, 6202, 5716, 5846, 6461, 5569, 6006, 5603, 6135, 6360, 5717, 6193, 5792, 5775, 5507, 6243, 5872, 6499, 5736, 6158, 6340, 5995, 6311, 6258, 5938, 6479, 5572, 5882, 6195, 6297, 5943, 5825, 6328, 6330, 5679, 6319, 6236, 6485, 6414, 5908, 6001, 5558, 6396, 6486, 5757, 5803, 5700, 5593, 5866, 6433, 5726, 6240, 5830, 6449, 5575, 6478, 5564, 5915, 6034, 6072, 6484, 6375, 5976, 5631, 6138, 5659, 6346, 6118, 6279, 5554, 6283, 5800, 5594, 5701, 6292, 5842, 5518, 6335, 5750, 6196, 5749, 6329, 6369, 5760, 6134, 5661, 6188, 5542, 6127, 6062, 6352, 6270, 5761, 6165, 6376, 6049, 5687, 6364, 5696, 6367, 5990, 5771, 6057, 6094, 5815, 6039, 5759, 5949, 5563, 5590, 5853, 6009, 5907, 5834, 5982, 5664, 6316, 5557, 6067, 6249, 6142, 6357, 5790, 5647, 5808, 5860, 6012] + +1000.times do + x = a1 | a2 + y = a2 | a1 +end diff --git a/benchmark/bm_array_union_objects.rb b/benchmark/bm_array_union_objects.rb new file mode 100644 index 00000000..2d2d2618 --- /dev/null +++ b/benchmark/bm_array_union_objects.rb @@ -0,0 +1,7 @@ +a1 = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] +a2 = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] + +1000.times do + x = a1 | a2 + y = a2 | a1 +end diff --git a/benchmark/bm_array_union_strings.rb b/benchmark/bm_array_union_strings.rb new file mode 100644 index 00000000..e4d4c4f8 --- /dev/null +++ b/benchmark/bm_array_union_strings.rb @@ -0,0 +1,7 @@ +a1 = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] +a2 = ['5650', '6274', '5600', '6197', '6324', '5850', '5630', '5955', '6343', '6233', '6065', '5637', '5561', '6500', '5565', '5845', '5916', '6229', '5857', '5747', '6419', '5936', '6363', '5773', '6399', '6350', '6172', '6494', '6042', '6013', '6132', '5887', '6215', '5837', '5663', '5695', '6453', '5698', '5941', '6186', '5902', '6116', '6487', '5945', '5694', '6392', '5605', '5524', '5884', '6470', '5503', '6458', '5910', '6469', '5645', '5540', '5505', '6136', '5715', '6306', '6164', '6406', '6120', '5919', '5592', '5595', '5684', '6464', '5958', '6060', '5862', '5672', '5670', '6211', '6321', '5654', '5516', '6278', '6084', '5867', '5577', '6379', '6139', '6472', '6251', '6460', '5831', '6133', '5772', '5788', '6260', '5580', '5912', '5865', '5616', '6153', '5567', '5709', '5963', '6489', '6344', '6113', '6409', '5987', '6141', '5508', '6093', '5723', '5883', '5829', '6086', '5774', '6026', '5601', '5859', '5517', '6252', '6412', '6481', '5828', '5556', '6234', '6416', '5562', '5992', '6045', '5559', '6309', '6109', '6273', '6407', '5743', '6338', '5706', '5719', '6430', '5693', '6247', '6450', '5710', '6015', '6429', '5607', '6056', '6495', '5613', '6370', '5671', '5751', '6237', '5748', '6217', '5977', '6194', '5511', '5599', '5624', '5923', '6452', '5841', '5798', '6025', '5879', '6420', '6177', '6294', '5871', '6105', '5822', '5770', '5724', '5754', '6063', '6291', '5529', '5921', '6018', '5856', '6058', '6372', '6361', '5889', '5899', '5555', '6454', '5960', '6411', '5512', '6069', '5913', '5502', '5821', '5965', '6475', '5697', '5523', '5676', '6076', '5648', '5769', '5948', '6493', '5683', '6200', '5651', '5653', '5885', '5667', '6404', '6432', '6226', '6102', '6213', '5796', '6462', '5811', '5764', '6100', '6073', '6117', '6147', '6373', '5777', '6221', '6184', '5553', '5731', '5536', '6288', '6204', '5586', '5707', '5753', '6362', '5602', '5924', '6231', '5832', '6264', '5968', '5597', '6467', '5946', '6212', '6275', '5509', '6156', '5582', '5816', '5909', '5791', '5952', '6442', '6474', '6023', '5939', '5649', '5531', '6259', '5994', '6388', '5776', '5641', '6068', '6477', '6220', '6286', '5897', '5873', '6381', '6339', '5652', '5589', '6302', '6227', '5544', '5793', '5892', '6488', '5506', '5876', '5781', '5576', '5521', '6331', '6131', '5617', '6332', '5801', '6107', '6463', '6457', '5802', '5737', '6104', '5550', '6253', '6368', '6050', '5766', '5534', '6224', '6401', '6303', '5786', '5735', '6282', '5596', '6459', '6122', '6492', '5854', '5988', '5549', '6318', '5840', '6178', '5640', '5752', '6040', '5665', '5755', '5535', '5721', '6088', '5914', '5689', '6256', '5838', '6021', '5674', '6028', '6223', '6189', '5886', '6232', '5878', '6424', '6413', '6482', '6155', '5638', '6160', '6440', '5571', '6037', '6323', '5959', '6468', '5826', '5682', '6327', '5514', '6390', '5510', '5870', '6108', '5722', '5934', '5998', '6402', '6348', '5718', '6471', '5942', '6029', '6185', '5926', '6386', '5940', '6443', '6230', '5855', '6349', '6059', '6276', '5740', '5996', '6238', '6287', '5812', '5578', '5658', '5525', '6380', '6095', '6112', '5925', '6246', '5985', '5692', '6261', '5734', '6337', '5966', '6004', '6151', '6161', '5917', '5863', '6300', '5732', '5547', '5851', '6295', '5787', '5864', '5545', '6356', '6175', '6154', '5680', '5799', '5500', '5969', '6301', '5622', '6071', '6030', '5655', '6299', '5519', '5818', '6064', '6054', '5646', '6166', '6272', '5610', '5705', '5956', '5820', '5920', '5581', '6268', '6027', '6074', '6087', '5668', '5794', '5880', '6173', '6434', '6374', '6008', '5807', '5739', '6307', '6437', '5619', '6451', '5618', '5628', '5932', '6235', '6190', '6225', '5629', '5911', '6257', '6410', '6304', '6140', '6395', '5817', '6284', '5927', '6010', '5639', '5758', '6098', '6051', '6239', '5979', '6281', '6417', '5903', '5675', '6456', '5795', '5527', '6242', '6387', '6090', '5623', '5890', '6322', '6418', '6110', '6254', '5620', '5537', '5573', '6359', '5612', '6325', '5513', '6044', '5918', '6473', '6148', '6341', '5543', '6448', '6101', '6280', '6222', '6438', '5981', '6152', '5532', '5626', '6491', '5591', '6170', '5953', '6115', '5744', '6179', '5632', '5861', '6421', '6377', '6245', '5852', '5835', '5625', '6289', '5657', '6111', '5768', '5504', '5741', '5606', '6480', '6167', '6096', '6005', '5522', '5974', '6435', '5643', '6290', '5780', '6444', '6083', '5989', '5893', '5539', '6347', '6016', '6210', '6391', '5789', '5967', '5778', '6035', '6476', '5836', '5702', '6003', '5881', '5714', '6002', '6024', '6203', '6119', '5656', '5691', '5944', '5935', '6046', '5763', '6032', '6266', '6250', '5997', '6207', '6092', '6103', '6043', '5999', '5725', '5552', '6007', '6314', '6159', '5844', '5633', '6269', '5720', '5961', '5583', '6446', '5877', '6171', '6199', '6315', '6271', '5756', '6497', '6383', '5704', '5585', '6144', '6384', '6426', '6285', '5611', '6439', '6351', '5574', '5609', '5905', '5538', '5824', '6149', '6036', '5728', '5515', '5929', '6422', '5644', '6366', '5900', '6354', '6121', '5669', '6394', '5703', '5978', '6022', '6085', '5604', '6436', '5688', '6079', '5767', '6378', '5541', '6398', '6265', '6174', '5809', '5819', '6428', '6163', '5660', '6342', '6097', '6128', '6114', '6183', '5685', '5711', '6277', '6089', '5584', '6201', '6305', '6427', '5975', '5642', '6048', '6091', '6130', '5673', '5621', '5993', '5528', '6353', '6345', '6241', '6041', '6137', '6019', '5810', '6385', '6000', '6169', '6298', '6078', '5699', '6358', '5588', '5546', '5678', '5627', '6106', '5785', '6055', '6425', '5906', '5928', '6415', '6182', '6075', '5962', '6052', '6382', '6145', '6129', '6498', '5904', '5779', '5520', '5784', '5783', '6334', '5970', '6205', '5847', '6441', '6066', '6365', '6176', '5849', '6371', '6326', '5686', '5708', '6180', '5814', '5636', '6431', '6405', '6070', '5869', '6077', '5738', '6080', '6496', '5950', '5806', '5782', '5827', '5896', '5598', '5746', '6014', '5742', '6465', '6123', '5964', '6038', '6218', '6020', '5727', '5888', '5530', '6389', '6061', '6483', '6031', '5901', '6393', '6466', '6320', '5666', '5805', '6168', '5986', '5833', '6143', '6181', '5635', '5681', '6447', '6047', '5570', '5898', '5560', '5931', '6126', '6053', '5823', '5566', '5526', '5858', '5548', '6209', '6336', '6011', '5587', '5677', '6082', '5891', '5839', '5874', '5579', '6214', '6397', '5568', '6263', '5991', '5972', '6081', '6490', '6267', '6310', '6248', '5937', '6216', '6333', '5608', '5875', '5551', '6445', '5983', '5848', '5954', '6262', '5762', '6146', '6191', '6206', '6355', '6244', '5868', '5980', '6423', '5922', '6099', '5933', '5614', '5713', '6317', '6312', '5984', '6255', '6187', '6162', '5930', '5690', '5813', '6192', '6400', '5533', '5973', '6150', '6308', '6313', '6125', '6124', '5733', '5951', '5957', '5662', '5765', '5501', '5894', '5797', '5729', '5730', '6403', '6033', '6455', '5895', '6017', '5712', '6219', '5615', '6208', '6198', '6157', '5634', '6408', '5947', '5745', '5971', '6228', '6296', '5843', '5804', '6293', '6202', '5716', '5846', '6461', '5569', '6006', '5603', '6135', '6360', '5717', '6193', '5792', '5775', '5507', '6243', '5872', '6499', '5736', '6158', '6340', '5995', '6311', '6258', '5938', '6479', '5572', '5882', '6195', '6297', '5943', '5825', '6328', '6330', '5679', '6319', '6236', '6485', '6414', '5908', '6001', '5558', '6396', '6486', '5757', '5803', '5700', '5593', '5866', '6433', '5726', '6240', '5830', '6449', '5575', '6478', '5564', '5915', '6034', '6072', '6484', '6375', '5976', '5631', '6138', '5659', '6346', '6118', '6279', '5554', '6283', '5800', '5594', '5701', '6292', '5842', '5518', '6335', '5750', '6196', '5749', '6329', '6369', '5760', '6134', '5661', '6188', '5542', '6127', '6062', '6352', '6270', '5761', '6165', '6376', '6049', '5687', '6364', '5696', '6367', '5990', '5771', '6057', '6094', '5815', '6039', '5759', '5949', '5563', '5590', '5853', '6009', '5907', '5834', '5982', '5664', '6316', '5557', '6067', '6249', '6142', '6357', '5790', '5647', '5808', '5860', '6012'] + +1000.times do + x = a1 | a2 + y = a2 | a1 +end diff --git a/benchmark/bm_array_uniq_bang_numbers.rb b/benchmark/bm_array_uniq_bang_numbers.rb new file mode 100644 index 00000000..8c36a6a1 --- /dev/null +++ b/benchmark/bm_array_uniq_bang_numbers.rb @@ -0,0 +1,5 @@ +a = [4768, 4964, 4266, 4872, 4231, 4017, 4565, 4793, 4298, 4135, 4639, 4780, 4237, 4548, 4655, 4153, 4654, 4922, 4563, 4042, 4329, 4699, 4352, 4127, 4544, 4906, 4814, 4948, 4977, 4830, 4405, 4642, 4666, 4402, 4679, 4465, 4401, 4155, 4767, 4510, 4747, 4993, 4508, 4697, 4758, 4133, 4348, 4200, 4442, 4970, 4452, 4041, 4103, 4567, 4937, 4047, 4933, 4121, 4860, 4659, 4221, 4312, 4583, 4473, 4973, 4262, 4630, 4123, 4139, 4289, 4147, 4222, 4050, 4019, 4454, 4253, 4552, 4947, 4725, 4457, 4929, 4021, 4502, 4307, 4576, 4124, 4586, 4610, 4027, 4572, 4926, 4753, 4185, 4382, 4394, 4923, 4186, 4254, 4012, 4417, 4556, 4349, 4550, 4330, 4938, 4985, 4778, 4716, 4924, 4045, 4358, 4189, 4591, 4213, 4851, 4825, 4260, 4198, 4342, 4824, 4333, 4244, 4752, 4994, 4488, 4532, 4082, 4595, 4098, 4436, 4540, 4267, 4407, 4998, 4751, 4535, 4861, 4819, 4419, 4031, 4029, 4453, 4698, 4965, 4450, 4668, 4036, 4300, 4519, 4281, 4981, 4818, 4939, 4378, 4140, 4841, 4249, 4290, 4388, 4878, 4884, 4235, 4515, 4638, 4410, 4054, 4383, 4238, 4870, 4295, 4804, 4308, 4614, 4105, 4053, 4446, 4757, 4971, 4637, 4831, 4193, 4912, 4000, 4187, 4606, 4566, 4169, 4641, 4749, 4729, 4928, 4601, 4949, 4210, 4313, 4647, 4495, 4460, 4621, 4605, 4694, 4317, 4226, 4263, 4016, 4997, 4940, 4715, 4907, 4620, 4934, 4996, 4955, 4688, 4304, 4220, 4882, 4772, 4536, 4815, 4693, 4469, 4276, 4409, 4071, 4224, 4020, 4629, 4865, 4813, 4366, 4622, 4129, 4533, 4634, 4564, 4087, 4386, 4161, 4265, 4711, 4009, 4376, 4781, 4837, 4112, 4915, 4592, 4658, 4025, 4987, 4291, 4477, 4503, 4437, 4111, 4707, 4879, 4611, 4549, 4078, 4044, 4853, 4835, 4463, 4577, 4008, 4233, 4741, 4384, 4225, 4024, 4726, 4743, 4160, 4180, 4722, 4609, 4114, 4834, 4742, 4662, 4984, 4299, 4060, 4498, 4755, 4320, 4874, 4528, 4216, 4852, 4951, 4958, 4283, 4239, 4476, 4644, 4143, 4104, 4455, 4126, 4950, 4663, 4013, 4931, 4850, 4242, 4130, 4623, 4871, 4014, 4854, 4293, 4512, 4166, 4740, 4735, 4150, 4651, 4172, 4836, 4530, 4664, 4429, 4511, 4558, 4676, 4085, 4074, 4580, 4794, 4379, 4310, 4817, 4966, 4848, 4202, 4336, 4608, 4351, 4396, 4652, 4033, 4188, 4431, 4916, 4259, 4607, 4816, 4810, 4627, 4527, 4560, 4728, 4589, 4274, 4809, 4790, 4398, 4414, 4516, 4581, 4919, 4665, 4331, 4978, 4543, 4877, 4974, 4284, 4004, 4177, 4466, 4116, 4217, 4901, 4372, 4137, 4806, 4264, 4497, 4294, 4787, 4212, 4215, 4115, 4782, 4739, 4821, 4125, 4505, 4230, 4399, 4395, 4079, 4867, 4381, 4706, 4695, 4404, 4691, 4075, 4353, 4301, 4876, 4731, 4523, 4246, 4529, 4412, 4784, 4449, 4229, 4616, 4158, 4002, 4318, 4377, 4205, 4911, 4777, 4792, 4271, 4763, 4141, 4287, 4890, 4279, 4829, 4646, 4840, 4089, 4880, 4067, 4918, 4059, 4109, 4164, 4863, 4883, 4909, 4361, 4174, 4960, 4302, 4003, 4236, 4846, 4034, 4324, 4513, 4765, 4596, 4900, 4007, 4603, 4474, 4439, 4805, 4015, 4496, 4953, 4363, 4551, 4459, 4063, 4983, 4881, 4365, 4604, 4587, 4798, 4005, 4163, 4421, 4471, 4826, 4144, 4635, 4600, 4913, 4640, 4247, 4766, 4779, 4280, 4391, 4891, 4636, 4546, 4683, 4181, 4081, 4862, 4458, 4037, 4321, 4786, 4717, 4628, 4154, 4326, 4032, 4873, 4151, 4905, 4270, 4156, 4733, 4980, 4866, 4325, 4055, 4467, 4480, 4286, 4191, 4762, 4322, 4574, 4022, 4056, 4770, 4451, 4448, 4845, 4341, 4433, 4245, 4684, 4671, 4093, 4920, 4272, 4745, 4799, 4761, 4250, 4578, 4347, 4499, 4526, 4369, 4162, 4537, 4434, 4893, 4120, 4962, 4667, 4525, 4091, 4462, 4182, 4738, 4935, 4173, 4490, 4571, 4424, 4894, 4051, 4214, 4823, 4096, 4206, 4598, 4943, 4701, 4649, 4807, 4107, 4435, 4456, 4083, 4612, 4721, 4472, 4146, 4925, 4340, 4789, 4277, 4375, 4211, 4427, 4547, 4690, 4613, 4727, 4006, 4203, 4430, 4223, 4039, 4932, 4296, 4108, 4278, 4832, 4422, 4917, 4470, 4183, 4887, 4076, 4485, 4597, 4443, 4257, 4991, 4944, 4196, 4672, 4397, 4097, 4119, 4077, 4773, 4602, 4538, 4479, 4968, 4159, 4539, 4956, 4710, 4812, 4902, 4569, 4954, 4385, 4128, 4936, 4416, 4148, 4632, 4759, 4117, 4896, 4392, 4864, 4316, 4132, 4319, 4969, 4175, 4484, 4903, 4910, 4350, 4332, 4952, 4176, 4594, 4709, 4509, 4178, 4167, 4545, 4857, 4617, 4501, 4859, 4207, 4275, 4687, 4049, 4579, 4046, 4921, 4113, 4898, 4681, 4052, 4415, 4064, 4184, 4895, 4744, 4685, 4084, 4305, 4899, 4559, 4208, 4057, 4507, 4258, 4355, 4086, 4373, 4323, 4541, 4297, 4483, 4889, 4531, 4327, 4441, 4914, 4303, 4677, 4445, 4802, 4343, 4585, 4338, 4524, 4590, 4624, 4288, 4704, 4134, 4043, 4720, 4058, 4328, 4095, 4026, 4423, 4657, 4118, 4633, 4487, 4822, 4904, 4255, 4001, 4387, 4500, 4190, 4686, 4995, 4661, 4783, 4992, 4165, 4065, 4927, 4306, 4856, 4292, 4420, 4963, 4468, 4240, 4724, 4432, 4447, 4518, 4028, 4670, 4339, 4771, 4018, 4489, 4110, 4708, 4945, 4136, 4492, 4930, 4090, 4734, 4886, 4542, 4227, 4486, 4491, 4713, 4986, 4068, 4048, 4975, 4570, 4842, 4475, 4131, 4555, 4428, 4776, 4101, 4273, 4811, 4345, 5000, 4653, 4256, 4209, 4769, 4946, 4561, 4080, 4461, 4820, 4311, 4959, 4750, 4795, 4748, 4368, 4506, 4335, 4346, 4568, 4675, 4692, 4774, 4413, 4370, 4723, 4521, 4885, 4678, 4897, 4066, 4674, 4106, 4626, 4389, 4204, 4839, 4023, 4712, 4145, 4035, 4357, 4756, 4648, 4972, 4157, 4406, 4615, 4061, 4219, 4791, 4660, 4073, 4356, 4072, 4599, 4359, 4094, 4673, 4696, 4796, 4282, 4714, 4522, 4736, 4775, 4760, 4400, 4847, 4228, 4803, 4908, 4732, 4645, 4122, 4218, 4478, 4941, 4892, 4364, 4403, 4152, 4444, 4360, 4354, 4241, 4494, 4367, 4808, 4261, 4088, 4573, 4554, 4248, 4371, 4393, 4268, 4201, 4038, 4788, 4593, 4040, 4801, 4582, 4309, 4976, 4374, 4869, 4380, 4514, 4243, 4362, 4849, 4680, 4888, 4764, 4618, 4838, 4828, 4643, 4010, 4827, 4957, 4099, 4875, 4843, 4737, 4102, 4979, 4011, 4504, 4440, 4746, 4557, 4426, 4553, 4656, 4868, 4689, 4988, 4703, 4967, 4069, 4619, 4334, 4669, 4785, 4464, 4562, 4961, 4625, 4754, 4797, 4481, 4705, 4199, 4337, 4062, 4138, 4702, 4534, 4168, 4418, 4092, 4682, 4520, 4030, 4171, 4650, 4858, 4411, 4999, 4252, 4197, 4170, 4942, 4631, 4990, 4179, 4285, 4700, 4482, 4575, 4800, 4070, 4251, 4344, 4982, 4719, 4390, 4149, 4100, 4194, 4269, 4855, 4314, 4718, 4232, 4730, 4438, 4588, 4195, 4192, 4493, 4517, 4833, 4234, 4989, 4315, 4844, 4142, 4408, 4584, 4425] + +1000.times do + a.uniq! +end diff --git a/benchmark/bm_array_uniq_bang_objects.rb b/benchmark/bm_array_uniq_bang_objects.rb new file mode 100644 index 00000000..11e163b7 --- /dev/null +++ b/benchmark/bm_array_uniq_bang_objects.rb @@ -0,0 +1,5 @@ +a = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] + +1000.times do + a.uniq! +end diff --git a/benchmark/bm_array_uniq_bang_strings.rb b/benchmark/bm_array_uniq_bang_strings.rb new file mode 100644 index 00000000..1e9b2d3b --- /dev/null +++ b/benchmark/bm_array_uniq_bang_strings.rb @@ -0,0 +1,5 @@ +a = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] + +1000.times do + a.uniq! +end diff --git a/benchmark/bm_array_uniq_numbers.rb b/benchmark/bm_array_uniq_numbers.rb new file mode 100644 index 00000000..1f3630a2 --- /dev/null +++ b/benchmark/bm_array_uniq_numbers.rb @@ -0,0 +1,5 @@ +a = [4768, 4964, 4266, 4872, 4231, 4017, 4565, 4793, 4298, 4135, 4639, 4780, 4237, 4548, 4655, 4153, 4654, 4922, 4563, 4042, 4329, 4699, 4352, 4127, 4544, 4906, 4814, 4948, 4977, 4830, 4405, 4642, 4666, 4402, 4679, 4465, 4401, 4155, 4767, 4510, 4747, 4993, 4508, 4697, 4758, 4133, 4348, 4200, 4442, 4970, 4452, 4041, 4103, 4567, 4937, 4047, 4933, 4121, 4860, 4659, 4221, 4312, 4583, 4473, 4973, 4262, 4630, 4123, 4139, 4289, 4147, 4222, 4050, 4019, 4454, 4253, 4552, 4947, 4725, 4457, 4929, 4021, 4502, 4307, 4576, 4124, 4586, 4610, 4027, 4572, 4926, 4753, 4185, 4382, 4394, 4923, 4186, 4254, 4012, 4417, 4556, 4349, 4550, 4330, 4938, 4985, 4778, 4716, 4924, 4045, 4358, 4189, 4591, 4213, 4851, 4825, 4260, 4198, 4342, 4824, 4333, 4244, 4752, 4994, 4488, 4532, 4082, 4595, 4098, 4436, 4540, 4267, 4407, 4998, 4751, 4535, 4861, 4819, 4419, 4031, 4029, 4453, 4698, 4965, 4450, 4668, 4036, 4300, 4519, 4281, 4981, 4818, 4939, 4378, 4140, 4841, 4249, 4290, 4388, 4878, 4884, 4235, 4515, 4638, 4410, 4054, 4383, 4238, 4870, 4295, 4804, 4308, 4614, 4105, 4053, 4446, 4757, 4971, 4637, 4831, 4193, 4912, 4000, 4187, 4606, 4566, 4169, 4641, 4749, 4729, 4928, 4601, 4949, 4210, 4313, 4647, 4495, 4460, 4621, 4605, 4694, 4317, 4226, 4263, 4016, 4997, 4940, 4715, 4907, 4620, 4934, 4996, 4955, 4688, 4304, 4220, 4882, 4772, 4536, 4815, 4693, 4469, 4276, 4409, 4071, 4224, 4020, 4629, 4865, 4813, 4366, 4622, 4129, 4533, 4634, 4564, 4087, 4386, 4161, 4265, 4711, 4009, 4376, 4781, 4837, 4112, 4915, 4592, 4658, 4025, 4987, 4291, 4477, 4503, 4437, 4111, 4707, 4879, 4611, 4549, 4078, 4044, 4853, 4835, 4463, 4577, 4008, 4233, 4741, 4384, 4225, 4024, 4726, 4743, 4160, 4180, 4722, 4609, 4114, 4834, 4742, 4662, 4984, 4299, 4060, 4498, 4755, 4320, 4874, 4528, 4216, 4852, 4951, 4958, 4283, 4239, 4476, 4644, 4143, 4104, 4455, 4126, 4950, 4663, 4013, 4931, 4850, 4242, 4130, 4623, 4871, 4014, 4854, 4293, 4512, 4166, 4740, 4735, 4150, 4651, 4172, 4836, 4530, 4664, 4429, 4511, 4558, 4676, 4085, 4074, 4580, 4794, 4379, 4310, 4817, 4966, 4848, 4202, 4336, 4608, 4351, 4396, 4652, 4033, 4188, 4431, 4916, 4259, 4607, 4816, 4810, 4627, 4527, 4560, 4728, 4589, 4274, 4809, 4790, 4398, 4414, 4516, 4581, 4919, 4665, 4331, 4978, 4543, 4877, 4974, 4284, 4004, 4177, 4466, 4116, 4217, 4901, 4372, 4137, 4806, 4264, 4497, 4294, 4787, 4212, 4215, 4115, 4782, 4739, 4821, 4125, 4505, 4230, 4399, 4395, 4079, 4867, 4381, 4706, 4695, 4404, 4691, 4075, 4353, 4301, 4876, 4731, 4523, 4246, 4529, 4412, 4784, 4449, 4229, 4616, 4158, 4002, 4318, 4377, 4205, 4911, 4777, 4792, 4271, 4763, 4141, 4287, 4890, 4279, 4829, 4646, 4840, 4089, 4880, 4067, 4918, 4059, 4109, 4164, 4863, 4883, 4909, 4361, 4174, 4960, 4302, 4003, 4236, 4846, 4034, 4324, 4513, 4765, 4596, 4900, 4007, 4603, 4474, 4439, 4805, 4015, 4496, 4953, 4363, 4551, 4459, 4063, 4983, 4881, 4365, 4604, 4587, 4798, 4005, 4163, 4421, 4471, 4826, 4144, 4635, 4600, 4913, 4640, 4247, 4766, 4779, 4280, 4391, 4891, 4636, 4546, 4683, 4181, 4081, 4862, 4458, 4037, 4321, 4786, 4717, 4628, 4154, 4326, 4032, 4873, 4151, 4905, 4270, 4156, 4733, 4980, 4866, 4325, 4055, 4467, 4480, 4286, 4191, 4762, 4322, 4574, 4022, 4056, 4770, 4451, 4448, 4845, 4341, 4433, 4245, 4684, 4671, 4093, 4920, 4272, 4745, 4799, 4761, 4250, 4578, 4347, 4499, 4526, 4369, 4162, 4537, 4434, 4893, 4120, 4962, 4667, 4525, 4091, 4462, 4182, 4738, 4935, 4173, 4490, 4571, 4424, 4894, 4051, 4214, 4823, 4096, 4206, 4598, 4943, 4701, 4649, 4807, 4107, 4435, 4456, 4083, 4612, 4721, 4472, 4146, 4925, 4340, 4789, 4277, 4375, 4211, 4427, 4547, 4690, 4613, 4727, 4006, 4203, 4430, 4223, 4039, 4932, 4296, 4108, 4278, 4832, 4422, 4917, 4470, 4183, 4887, 4076, 4485, 4597, 4443, 4257, 4991, 4944, 4196, 4672, 4397, 4097, 4119, 4077, 4773, 4602, 4538, 4479, 4968, 4159, 4539, 4956, 4710, 4812, 4902, 4569, 4954, 4385, 4128, 4936, 4416, 4148, 4632, 4759, 4117, 4896, 4392, 4864, 4316, 4132, 4319, 4969, 4175, 4484, 4903, 4910, 4350, 4332, 4952, 4176, 4594, 4709, 4509, 4178, 4167, 4545, 4857, 4617, 4501, 4859, 4207, 4275, 4687, 4049, 4579, 4046, 4921, 4113, 4898, 4681, 4052, 4415, 4064, 4184, 4895, 4744, 4685, 4084, 4305, 4899, 4559, 4208, 4057, 4507, 4258, 4355, 4086, 4373, 4323, 4541, 4297, 4483, 4889, 4531, 4327, 4441, 4914, 4303, 4677, 4445, 4802, 4343, 4585, 4338, 4524, 4590, 4624, 4288, 4704, 4134, 4043, 4720, 4058, 4328, 4095, 4026, 4423, 4657, 4118, 4633, 4487, 4822, 4904, 4255, 4001, 4387, 4500, 4190, 4686, 4995, 4661, 4783, 4992, 4165, 4065, 4927, 4306, 4856, 4292, 4420, 4963, 4468, 4240, 4724, 4432, 4447, 4518, 4028, 4670, 4339, 4771, 4018, 4489, 4110, 4708, 4945, 4136, 4492, 4930, 4090, 4734, 4886, 4542, 4227, 4486, 4491, 4713, 4986, 4068, 4048, 4975, 4570, 4842, 4475, 4131, 4555, 4428, 4776, 4101, 4273, 4811, 4345, 5000, 4653, 4256, 4209, 4769, 4946, 4561, 4080, 4461, 4820, 4311, 4959, 4750, 4795, 4748, 4368, 4506, 4335, 4346, 4568, 4675, 4692, 4774, 4413, 4370, 4723, 4521, 4885, 4678, 4897, 4066, 4674, 4106, 4626, 4389, 4204, 4839, 4023, 4712, 4145, 4035, 4357, 4756, 4648, 4972, 4157, 4406, 4615, 4061, 4219, 4791, 4660, 4073, 4356, 4072, 4599, 4359, 4094, 4673, 4696, 4796, 4282, 4714, 4522, 4736, 4775, 4760, 4400, 4847, 4228, 4803, 4908, 4732, 4645, 4122, 4218, 4478, 4941, 4892, 4364, 4403, 4152, 4444, 4360, 4354, 4241, 4494, 4367, 4808, 4261, 4088, 4573, 4554, 4248, 4371, 4393, 4268, 4201, 4038, 4788, 4593, 4040, 4801, 4582, 4309, 4976, 4374, 4869, 4380, 4514, 4243, 4362, 4849, 4680, 4888, 4764, 4618, 4838, 4828, 4643, 4010, 4827, 4957, 4099, 4875, 4843, 4737, 4102, 4979, 4011, 4504, 4440, 4746, 4557, 4426, 4553, 4656, 4868, 4689, 4988, 4703, 4967, 4069, 4619, 4334, 4669, 4785, 4464, 4562, 4961, 4625, 4754, 4797, 4481, 4705, 4199, 4337, 4062, 4138, 4702, 4534, 4168, 4418, 4092, 4682, 4520, 4030, 4171, 4650, 4858, 4411, 4999, 4252, 4197, 4170, 4942, 4631, 4990, 4179, 4285, 4700, 4482, 4575, 4800, 4070, 4251, 4344, 4982, 4719, 4390, 4149, 4100, 4194, 4269, 4855, 4314, 4718, 4232, 4730, 4438, 4588, 4195, 4192, 4493, 4517, 4833, 4234, 4989, 4315, 4844, 4142, 4408, 4584, 4425] + +1000.times do + x = a.uniq +end diff --git a/benchmark/bm_array_uniq_objects.rb b/benchmark/bm_array_uniq_objects.rb new file mode 100644 index 00000000..b1529961 --- /dev/null +++ b/benchmark/bm_array_uniq_objects.rb @@ -0,0 +1,5 @@ +a = [Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new, Object.new] + +1000.times do + x = a.uniq +end diff --git a/benchmark/bm_array_uniq_strings.rb b/benchmark/bm_array_uniq_strings.rb new file mode 100644 index 00000000..d44b326e --- /dev/null +++ b/benchmark/bm_array_uniq_strings.rb @@ -0,0 +1,5 @@ +a = ['4768', '4964', '4266', '4872', '4231', '4017', '4565', '4793', '4298', '4135', '4639', '4780', '4237', '4548', '4655', '4153', '4654', '4922', '4563', '4042', '4329', '4699', '4352', '4127', '4544', '4906', '4814', '4948', '4977', '4830', '4405', '4642', '4666', '4402', '4679', '4465', '4401', '4155', '4767', '4510', '4747', '4993', '4508', '4697', '4758', '4133', '4348', '4200', '4442', '4970', '4452', '4041', '4103', '4567', '4937', '4047', '4933', '4121', '4860', '4659', '4221', '4312', '4583', '4473', '4973', '4262', '4630', '4123', '4139', '4289', '4147', '4222', '4050', '4019', '4454', '4253', '4552', '4947', '4725', '4457', '4929', '4021', '4502', '4307', '4576', '4124', '4586', '4610', '4027', '4572', '4926', '4753', '4185', '4382', '4394', '4923', '4186', '4254', '4012', '4417', '4556', '4349', '4550', '4330', '4938', '4985', '4778', '4716', '4924', '4045', '4358', '4189', '4591', '4213', '4851', '4825', '4260', '4198', '4342', '4824', '4333', '4244', '4752', '4994', '4488', '4532', '4082', '4595', '4098', '4436', '4540', '4267', '4407', '4998', '4751', '4535', '4861', '4819', '4419', '4031', '4029', '4453', '4698', '4965', '4450', '4668', '4036', '4300', '4519', '4281', '4981', '4818', '4939', '4378', '4140', '4841', '4249', '4290', '4388', '4878', '4884', '4235', '4515', '4638', '4410', '4054', '4383', '4238', '4870', '4295', '4804', '4308', '4614', '4105', '4053', '4446', '4757', '4971', '4637', '4831', '4193', '4912', '4000', '4187', '4606', '4566', '4169', '4641', '4749', '4729', '4928', '4601', '4949', '4210', '4313', '4647', '4495', '4460', '4621', '4605', '4694', '4317', '4226', '4263', '4016', '4997', '4940', '4715', '4907', '4620', '4934', '4996', '4955', '4688', '4304', '4220', '4882', '4772', '4536', '4815', '4693', '4469', '4276', '4409', '4071', '4224', '4020', '4629', '4865', '4813', '4366', '4622', '4129', '4533', '4634', '4564', '4087', '4386', '4161', '4265', '4711', '4009', '4376', '4781', '4837', '4112', '4915', '4592', '4658', '4025', '4987', '4291', '4477', '4503', '4437', '4111', '4707', '4879', '4611', '4549', '4078', '4044', '4853', '4835', '4463', '4577', '4008', '4233', '4741', '4384', '4225', '4024', '4726', '4743', '4160', '4180', '4722', '4609', '4114', '4834', '4742', '4662', '4984', '4299', '4060', '4498', '4755', '4320', '4874', '4528', '4216', '4852', '4951', '4958', '4283', '4239', '4476', '4644', '4143', '4104', '4455', '4126', '4950', '4663', '4013', '4931', '4850', '4242', '4130', '4623', '4871', '4014', '4854', '4293', '4512', '4166', '4740', '4735', '4150', '4651', '4172', '4836', '4530', '4664', '4429', '4511', '4558', '4676', '4085', '4074', '4580', '4794', '4379', '4310', '4817', '4966', '4848', '4202', '4336', '4608', '4351', '4396', '4652', '4033', '4188', '4431', '4916', '4259', '4607', '4816', '4810', '4627', '4527', '4560', '4728', '4589', '4274', '4809', '4790', '4398', '4414', '4516', '4581', '4919', '4665', '4331', '4978', '4543', '4877', '4974', '4284', '4004', '4177', '4466', '4116', '4217', '4901', '4372', '4137', '4806', '4264', '4497', '4294', '4787', '4212', '4215', '4115', '4782', '4739', '4821', '4125', '4505', '4230', '4399', '4395', '4079', '4867', '4381', '4706', '4695', '4404', '4691', '4075', '4353', '4301', '4876', '4731', '4523', '4246', '4529', '4412', '4784', '4449', '4229', '4616', '4158', '4002', '4318', '4377', '4205', '4911', '4777', '4792', '4271', '4763', '4141', '4287', '4890', '4279', '4829', '4646', '4840', '4089', '4880', '4067', '4918', '4059', '4109', '4164', '4863', '4883', '4909', '4361', '4174', '4960', '4302', '4003', '4236', '4846', '4034', '4324', '4513', '4765', '4596', '4900', '4007', '4603', '4474', '4439', '4805', '4015', '4496', '4953', '4363', '4551', '4459', '4063', '4983', '4881', '4365', '4604', '4587', '4798', '4005', '4163', '4421', '4471', '4826', '4144', '4635', '4600', '4913', '4640', '4247', '4766', '4779', '4280', '4391', '4891', '4636', '4546', '4683', '4181', '4081', '4862', '4458', '4037', '4321', '4786', '4717', '4628', '4154', '4326', '4032', '4873', '4151', '4905', '4270', '4156', '4733', '4980', '4866', '4325', '4055', '4467', '4480', '4286', '4191', '4762', '4322', '4574', '4022', '4056', '4770', '4451', '4448', '4845', '4341', '4433', '4245', '4684', '4671', '4093', '4920', '4272', '4745', '4799', '4761', '4250', '4578', '4347', '4499', '4526', '4369', '4162', '4537', '4434', '4893', '4120', '4962', '4667', '4525', '4091', '4462', '4182', '4738', '4935', '4173', '4490', '4571', '4424', '4894', '4051', '4214', '4823', '4096', '4206', '4598', '4943', '4701', '4649', '4807', '4107', '4435', '4456', '4083', '4612', '4721', '4472', '4146', '4925', '4340', '4789', '4277', '4375', '4211', '4427', '4547', '4690', '4613', '4727', '4006', '4203', '4430', '4223', '4039', '4932', '4296', '4108', '4278', '4832', '4422', '4917', '4470', '4183', '4887', '4076', '4485', '4597', '4443', '4257', '4991', '4944', '4196', '4672', '4397', '4097', '4119', '4077', '4773', '4602', '4538', '4479', '4968', '4159', '4539', '4956', '4710', '4812', '4902', '4569', '4954', '4385', '4128', '4936', '4416', '4148', '4632', '4759', '4117', '4896', '4392', '4864', '4316', '4132', '4319', '4969', '4175', '4484', '4903', '4910', '4350', '4332', '4952', '4176', '4594', '4709', '4509', '4178', '4167', '4545', '4857', '4617', '4501', '4859', '4207', '4275', '4687', '4049', '4579', '4046', '4921', '4113', '4898', '4681', '4052', '4415', '4064', '4184', '4895', '4744', '4685', '4084', '4305', '4899', '4559', '4208', '4057', '4507', '4258', '4355', '4086', '4373', '4323', '4541', '4297', '4483', '4889', '4531', '4327', '4441', '4914', '4303', '4677', '4445', '4802', '4343', '4585', '4338', '4524', '4590', '4624', '4288', '4704', '4134', '4043', '4720', '4058', '4328', '4095', '4026', '4423', '4657', '4118', '4633', '4487', '4822', '4904', '4255', '4001', '4387', '4500', '4190', '4686', '4995', '4661', '4783', '4992', '4165', '4065', '4927', '4306', '4856', '4292', '4420', '4963', '4468', '4240', '4724', '4432', '4447', '4518', '4028', '4670', '4339', '4771', '4018', '4489', '4110', '4708', '4945', '4136', '4492', '4930', '4090', '4734', '4886', '4542', '4227', '4486', '4491', '4713', '4986', '4068', '4048', '4975', '4570', '4842', '4475', '4131', '4555', '4428', '4776', '4101', '4273', '4811', '4345', '5000', '4653', '4256', '4209', '4769', '4946', '4561', '4080', '4461', '4820', '4311', '4959', '4750', '4795', '4748', '4368', '4506', '4335', '4346', '4568', '4675', '4692', '4774', '4413', '4370', '4723', '4521', '4885', '4678', '4897', '4066', '4674', '4106', '4626', '4389', '4204', '4839', '4023', '4712', '4145', '4035', '4357', '4756', '4648', '4972', '4157', '4406', '4615', '4061', '4219', '4791', '4660', '4073', '4356', '4072', '4599', '4359', '4094', '4673', '4696', '4796', '4282', '4714', '4522', '4736', '4775', '4760', '4400', '4847', '4228', '4803', '4908', '4732', '4645', '4122', '4218', '4478', '4941', '4892', '4364', '4403', '4152', '4444', '4360', '4354', '4241', '4494', '4367', '4808', '4261', '4088', '4573', '4554', '4248', '4371', '4393', '4268', '4201', '4038', '4788', '4593', '4040', '4801', '4582', '4309', '4976', '4374', '4869', '4380', '4514', '4243', '4362', '4849', '4680', '4888', '4764', '4618', '4838', '4828', '4643', '4010', '4827', '4957', '4099', '4875', '4843', '4737', '4102', '4979', '4011', '4504', '4440', '4746', '4557', '4426', '4553', '4656', '4868', '4689', '4988', '4703', '4967', '4069', '4619', '4334', '4669', '4785', '4464', '4562', '4961', '4625', '4754', '4797', '4481', '4705', '4199', '4337', '4062', '4138', '4702', '4534', '4168', '4418', '4092', '4682', '4520', '4030', '4171', '4650', '4858', '4411', '4999', '4252', '4197', '4170', '4942', '4631', '4990', '4179', '4285', '4700', '4482', '4575', '4800', '4070', '4251', '4344', '4982', '4719', '4390', '4149', '4100', '4194', '4269', '4855', '4314', '4718', '4232', '4730', '4438', '4588', '4195', '4192', '4493', '4517', '4833', '4234', '4989', '4315', '4844', '4142', '4408', '4584', '4425'] + +1000.times do + x = a.uniq +end diff --git a/benchmark/bm_constant_lookup_big.rb b/benchmark/bm_constant_lookup_big.rb new file mode 100644 index 00000000..af2c2eee --- /dev/null +++ b/benchmark/bm_constant_lookup_big.rb @@ -0,0 +1,799 @@ +module Scope0 + CONST0 = 0 + module Scope1 + CONST1 = 1 + CONST0 + module Scope2 + CONST2 = 2 + CONST0 + module Scope3 + CONST3 = 3 + CONST1 + module Scope4 + CONST4 = 4 + CONST0 + module Scope5 + CONST5 = 5 + CONST2 + module Scope6 + CONST6 = 6 + CONST1 + module Scope7 + CONST7 = 7 + CONST3 + module Scope8 + CONST8 = 8 + CONST6 + module Scope9 + CONST9 = 9 + CONST1 + module Scope10 + CONST10 = 10 + CONST5 + module Scope11 + CONST11 = 11 + CONST10 + module Scope12 + CONST12 = 12 + CONST3 + module Scope13 + CONST13 = 13 + CONST8 + module Scope14 + CONST14 = 14 + CONST9 + module Scope15 + CONST15 = 15 + CONST12 + module Scope16 + CONST16 = 16 + CONST6 + module Scope17 + CONST17 = 17 + CONST2 + module Scope18 + CONST18 = 18 + CONST13 + module Scope19 + CONST19 = 19 + CONST7 + module Scope20 + CONST20 = 20 + CONST3 + module Scope21 + CONST21 = 21 + CONST0 + module Scope22 + CONST22 = 22 + CONST20 + module Scope23 + CONST23 = 23 + CONST3 + module Scope24 + CONST24 = 24 + CONST8 + module Scope25 + CONST25 = 25 + CONST5 + module Scope26 + CONST26 = 26 + CONST24 + module Scope27 + CONST27 = 27 + CONST19 + module Scope28 + CONST28 = 28 + CONST3 + module Scope29 + CONST29 = 29 + CONST5 + module Scope30 + CONST30 = 30 + CONST3 + module Scope31 + CONST31 = 31 + CONST12 + module Scope32 + CONST32 = 32 + CONST11 + module Scope33 + CONST33 = 33 + CONST31 + module Scope34 + CONST34 = 34 + CONST12 + module Scope35 + CONST35 = 35 + CONST5 + module Scope36 + CONST36 = 36 + CONST22 + module Scope37 + CONST37 = 37 + CONST20 + module Scope38 + CONST38 = 38 + CONST27 + module Scope39 + CONST39 = 39 + CONST7 + module Scope40 + CONST40 = 40 + CONST38 + module Scope41 + CONST41 = 41 + CONST35 + module Scope42 + CONST42 = 42 + CONST37 + module Scope43 + CONST43 = 43 + CONST32 + module Scope44 + CONST44 = 44 + CONST28 + module Scope45 + CONST45 = 45 + CONST20 + module Scope46 + CONST46 = 46 + CONST43 + module Scope47 + CONST47 = 47 + CONST2 + module Scope48 + CONST48 = 48 + CONST41 + module Scope49 + CONST49 = 49 + CONST46 + module Scope50 + CONST50 = 50 + CONST17 + module Scope51 + CONST51 = 51 + CONST38 + module Scope52 + CONST52 = 52 + CONST49 + module Scope53 + CONST53 = 53 + CONST9 + module Scope54 + CONST54 = 54 + CONST5 + module Scope55 + CONST55 = 55 + CONST41 + module Scope56 + CONST56 = 56 + CONST11 + module Scope57 + CONST57 = 57 + CONST48 + module Scope58 + CONST58 = 58 + CONST30 + module Scope59 + CONST59 = 59 + CONST53 + module Scope60 + CONST60 = 60 + CONST40 + module Scope61 + CONST61 = 61 + CONST42 + module Scope62 + CONST62 = 62 + CONST52 + module Scope63 + CONST63 = 63 + CONST15 + module Scope64 + CONST64 = 64 + CONST5 + module Scope65 + CONST65 = 65 + CONST62 + module Scope66 + CONST66 = 66 + CONST43 + module Scope67 + CONST67 = 67 + CONST24 + module Scope68 + CONST68 = 68 + CONST48 + module Scope69 + CONST69 = 69 + CONST34 + module Scope70 + CONST70 = 70 + CONST24 + module Scope71 + CONST71 = 71 + CONST12 + module Scope72 + CONST72 = 72 + CONST30 + module Scope73 + CONST73 = 73 + CONST72 + module Scope74 + CONST74 = 74 + CONST40 + module Scope75 + CONST75 = 75 + CONST36 + module Scope76 + CONST76 = 76 + CONST31 + module Scope77 + CONST77 = 77 + CONST30 + module Scope78 + CONST78 = 78 + CONST15 + module Scope79 + CONST79 = 79 + CONST1 + module Scope80 + CONST80 = 80 + CONST70 + module Scope81 + CONST81 = 81 + CONST4 + module Scope82 + CONST82 = 82 + CONST29 + module Scope83 + CONST83 = 83 + CONST31 + module Scope84 + CONST84 = 84 + CONST49 + module Scope85 + CONST85 = 85 + CONST14 + module Scope86 + CONST86 = 86 + CONST34 + module Scope87 + CONST87 = 87 + CONST65 + module Scope88 + CONST88 = 88 + CONST48 + module Scope89 + CONST89 = 89 + CONST70 + module Scope90 + CONST90 = 90 + CONST80 + module Scope91 + CONST91 = 91 + CONST67 + module Scope92 + CONST92 = 92 + CONST34 + module Scope93 + CONST93 = 93 + CONST1 + module Scope94 + CONST94 = 94 + CONST48 + module Scope95 + CONST95 = 95 + CONST18 + module Scope96 + CONST96 = 96 + CONST1 + module Scope97 + CONST97 = 97 + CONST38 + module Scope98 + CONST98 = 98 + CONST37 + module Scope99 + CONST99 = 99 + CONST19 + module Scope100 + CONST100 = 100 + CONST45 + module Scope101 + CONST101 = 101 + CONST26 + module Scope102 + CONST102 = 102 + CONST94 + module Scope103 + CONST103 = 103 + CONST1 + module Scope104 + CONST104 = 104 + CONST65 + module Scope105 + CONST105 = 105 + CONST20 + module Scope106 + CONST106 = 106 + CONST33 + module Scope107 + CONST107 = 107 + CONST51 + module Scope108 + CONST108 = 108 + CONST34 + module Scope109 + CONST109 = 109 + CONST104 + module Scope110 + CONST110 = 110 + CONST98 + module Scope111 + CONST111 = 111 + CONST64 + module Scope112 + CONST112 = 112 + CONST38 + module Scope113 + CONST113 = 113 + CONST23 + module Scope114 + CONST114 = 114 + CONST54 + module Scope115 + CONST115 = 115 + CONST44 + module Scope116 + CONST116 = 116 + CONST7 + module Scope117 + CONST117 = 117 + CONST45 + module Scope118 + CONST118 = 118 + CONST40 + module Scope119 + CONST119 = 119 + CONST34 + module Scope120 + CONST120 = 120 + CONST111 + module Scope121 + CONST121 = 121 + CONST15 + module Scope122 + CONST122 = 122 + CONST111 + module Scope123 + CONST123 = 123 + CONST114 + module Scope124 + CONST124 = 124 + CONST1 + module Scope125 + CONST125 = 125 + CONST106 + module Scope126 + CONST126 = 126 + CONST42 + module Scope127 + CONST127 = 127 + CONST39 + module Scope128 + CONST128 = 128 + CONST124 + module Scope129 + CONST129 = 129 + CONST90 + module Scope130 + CONST130 = 130 + CONST57 + module Scope131 + CONST131 = 131 + CONST53 + module Scope132 + CONST132 = 132 + CONST38 + module Scope133 + CONST133 = 133 + CONST46 + module Scope134 + CONST134 = 134 + CONST20 + module Scope135 + CONST135 = 135 + CONST75 + module Scope136 + CONST136 = 136 + CONST25 + module Scope137 + CONST137 = 137 + CONST26 + module Scope138 + CONST138 = 138 + CONST26 + module Scope139 + CONST139 = 139 + CONST26 + module Scope140 + CONST140 = 140 + CONST110 + module Scope141 + CONST141 = 141 + CONST20 + module Scope142 + CONST142 = 142 + CONST31 + module Scope143 + CONST143 = 143 + CONST9 + module Scope144 + CONST144 = 144 + CONST23 + module Scope145 + CONST145 = 145 + CONST68 + module Scope146 + CONST146 = 146 + CONST144 + module Scope147 + CONST147 = 147 + CONST19 + module Scope148 + CONST148 = 148 + CONST38 + module Scope149 + CONST149 = 149 + CONST136 + module Scope150 + CONST150 = 150 + CONST143 + module Scope151 + CONST151 = 151 + CONST34 + module Scope152 + CONST152 = 152 + CONST53 + module Scope153 + CONST153 = 153 + CONST20 + module Scope154 + CONST154 = 154 + CONST81 + module Scope155 + CONST155 = 155 + CONST69 + module Scope156 + CONST156 = 156 + CONST55 + module Scope157 + CONST157 = 157 + CONST6 + module Scope158 + CONST158 = 158 + CONST73 + module Scope159 + CONST159 = 159 + CONST31 + module Scope160 + CONST160 = 160 + CONST95 + module Scope161 + CONST161 = 161 + CONST148 + module Scope162 + CONST162 = 162 + CONST152 + module Scope163 + CONST163 = 163 + CONST108 + module Scope164 + CONST164 = 164 + CONST157 + module Scope165 + CONST165 = 165 + CONST40 + module Scope166 + CONST166 = 166 + CONST104 + module Scope167 + CONST167 = 167 + CONST61 + module Scope168 + CONST168 = 168 + CONST114 + module Scope169 + CONST169 = 169 + CONST36 + module Scope170 + CONST170 = 170 + CONST85 + module Scope171 + CONST171 = 171 + CONST153 + module Scope172 + CONST172 = 172 + CONST117 + module Scope173 + CONST173 = 173 + CONST45 + module Scope174 + CONST174 = 174 + CONST47 + module Scope175 + CONST175 = 175 + CONST25 + module Scope176 + CONST176 = 176 + CONST12 + module Scope177 + CONST177 = 177 + CONST38 + module Scope178 + CONST178 = 178 + CONST33 + module Scope179 + CONST179 = 179 + CONST178 + module Scope180 + CONST180 = 180 + CONST33 + module Scope181 + CONST181 = 181 + CONST4 + module Scope182 + CONST182 = 182 + CONST66 + module Scope183 + CONST183 = 183 + CONST75 + module Scope184 + CONST184 = 184 + CONST30 + module Scope185 + CONST185 = 185 + CONST141 + module Scope186 + CONST186 = 186 + CONST124 + module Scope187 + CONST187 = 187 + CONST27 + module Scope188 + CONST188 = 188 + CONST180 + module Scope189 + CONST189 = 189 + CONST39 + module Scope190 + CONST190 = 190 + CONST110 + module Scope191 + CONST191 = 191 + CONST112 + module Scope192 + CONST192 = 192 + CONST16 + module Scope193 + CONST193 = 193 + CONST131 + module Scope194 + CONST194 = 194 + CONST51 + module Scope195 + CONST195 = 195 + CONST130 + module Scope196 + CONST196 = 196 + CONST151 + module Scope197 + CONST197 = 197 + CONST74 + module Scope198 + CONST198 = 198 + CONST181 + module Scope199 + CONST199 = 199 + CONST20 + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end +end diff --git a/benchmark/bm_constant_lookup_small.rb b/benchmark/bm_constant_lookup_small.rb new file mode 100644 index 00000000..13e7d2c3 --- /dev/null +++ b/benchmark/bm_constant_lookup_small.rb @@ -0,0 +1,59 @@ +module Scope0 + CONST0 = 0 + module Scope1 + CONST1 = 1 + CONST0 + module Scope2 + CONST2 = 2 + CONST1 + module Scope3 + CONST3 = 3 + CONST0 + module Scope4 + CONST4 = 4 + CONST0 + module Scope5 + CONST5 = 5 + CONST4 + module Scope6 + CONST6 = 6 + CONST4 + module Scope7 + CONST7 = 7 + CONST5 + module Scope8 + CONST8 = 8 + CONST7 + module Scope9 + CONST9 = 9 + CONST8 + module Scope10 + CONST10 = 10 + CONST4 + module Scope11 + CONST11 = 11 + CONST7 + module Scope12 + CONST12 = 12 + CONST1 + module Scope13 + CONST13 = 13 + CONST11 + module Scope14 + CONST14 = 14 + CONST13 + end + end + end + end + end + end + end + end + end + end + end + end + end + end +end diff --git a/benchmark/bm_dispatch_bind_table.rb b/benchmark/bm_dispatch_bind_table.rb new file mode 100644 index 00000000..9b47d922 --- /dev/null +++ b/benchmark/bm_dispatch_bind_table.rb @@ -0,0 +1,57 @@ +class BindTableDispatch + attr_reader :event_log + + def initialize + @event_log = [] + end + + def self.method_added_cheat(method_name) + if method_name.to_s =~ /^handle_(.+)$/ + handler_methods[$1.to_sym] = instance_method(method_name) + end + # Cheating here, because Opal does not support method_added hook yet + # Uncomment the super below when it does: + # super + end + + def self.handler_methods + @handler_methods ||= {} + end + + def call(event) + if (handler_method = self.class.handler_methods[event.name]) + handler_method.bind(self).call(event) + end + end + + def handle_foo(event) + event_log << event + end + + def handle_bar(event) + event_log << event + end + + def handle_baz(event) + event_log << event + end +end + +klass = BindTableDispatch +event = Struct.new(:name, :source, :args) + +# Cheating here, because Opal does not support method_added hook yet +klass.method_added_cheat(:handle_foo) +klass.method_added_cheat(:handle_bar) +klass.method_added_cheat(:handle_baz) + +100_000.times do + obj = klass.new + obj.call(e1 = event[:foo]) + obj.call(e2 = event[:bar]) + obj.call(e3 = event[:baz]) + obj.call(event[:buz]) + unless obj.event_log == [e1, e2, e3] + raise "#{klass}: #{obj.event_log.inspect}" + end +end diff --git a/benchmark/bm_dispatch_code_gen.rb b/benchmark/bm_dispatch_code_gen.rb new file mode 100644 index 00000000..ba1fc98f --- /dev/null +++ b/benchmark/bm_dispatch_code_gen.rb @@ -0,0 +1,65 @@ +class CodeGenDispatch + attr_reader :event_log + + def initialize + @event_log = [] + end + + def self.method_added_cheat(method_name) + if method_name.to_s =~ /^handle_(.+)$/ + handler_methods << $1 + regenerate_dispatch_method + end + # Cheating here, because Opal does not support method_added hook yet + # Uncomment the super below when it does: + # super + end + + def self.handler_methods + @handler_methods ||= [] + end + + def self.regenerate_dispatch_method + dispatch_table = handler_methods.map { |event_name| + "when :#{event_name} then handle_#{event_name}(event)" + }.join("\n") + class_eval %{ + def call(event) + case event.name + #{dispatch_table} + end + end + } + end + + def handle_foo(event) + event_log << event + end + + def handle_bar(event) + event_log << event + end + + def handle_baz(event) + event_log << event + end +end + +klass = CodeGenDispatch +event = Struct.new(:name, :source, :args) + +# Cheating here, because Opal does not support method_added hook yet +klass.method_added_cheat(:handle_foo) +klass.method_added_cheat(:handle_bar) +klass.method_added_cheat(:handle_baz) + +100_000.times do + obj = klass.new + obj.call(e1 = event[:foo]) + obj.call(e2 = event[:bar]) + obj.call(e3 = event[:baz]) + obj.call(event[:buz]) + unless obj.event_log == [e1, e2, e3] + raise "#{klass}: #{obj.event_log.inspect}" + end +end diff --git a/benchmark/bm_dispatch_code_gen_if.rb b/benchmark/bm_dispatch_code_gen_if.rb new file mode 100644 index 00000000..b38e6ad9 --- /dev/null +++ b/benchmark/bm_dispatch_code_gen_if.rb @@ -0,0 +1,64 @@ +class IfCodeGenDispatch + attr_reader :event_log + + def initialize + @event_log = [] + end + + def self.method_added_cheat(method_name) + if method_name.to_s =~ /^handle_(.+)$/ + handler_methods << $1 + regenerate_dispatch_method + end + # Cheating here, because Opal does not support method_added hook yet + # Uncomment the super below when it does: + # super + end + + def self.handler_methods + @handler_methods ||= [] + end + + def self.regenerate_dispatch_method + dispatch_table = handler_methods.map { |event_name| + "event.name.equal?(:#{event_name}) then handle_#{event_name}(event)" + }.join("\nelsif ") + class_eval %{ + def call(event) + if #{dispatch_table} + end + end + } + end + + def handle_foo(event) + event_log << event + end + + def handle_bar(event) + event_log << event + end + + def handle_baz(event) + event_log << event + end +end + +klass = IfCodeGenDispatch +event = Struct.new(:name, :source, :args) + +# Cheating here, because Opal does not support method_added hook yet +klass.method_added_cheat(:handle_foo) +klass.method_added_cheat(:handle_bar) +klass.method_added_cheat(:handle_baz) + +100_000.times do + obj = klass.new + obj.call(e1 = event[:foo]) + obj.call(e2 = event[:bar]) + obj.call(e3 = event[:baz]) + obj.call(event[:buz]) + unless obj.event_log == [e1, e2, e3] + raise "#{klass}: #{obj.event_log.inspect}" + end +end diff --git a/benchmark/bm_dispatch_hardcoded.rb b/benchmark/bm_dispatch_hardcoded.rb new file mode 100644 index 00000000..433e77a1 --- /dev/null +++ b/benchmark/bm_dispatch_hardcoded.rb @@ -0,0 +1,44 @@ +class HardcodedDispatch + attr_reader :event_log + + def initialize + @event_log = [] + end + + def call(event) + case event.name + when :foo + handle_foo(event) + when :bar + handle_bar(event) + when :baz + handle_baz(event) + end + end + + def handle_foo(event) + event_log << event + end + + def handle_bar(event) + event_log << event + end + + def handle_baz(event) + event_log << event + end +end + +klass = HardcodedDispatch +event = Struct.new(:name, :source, :args) + +100_000.times do + obj = klass.new + obj.call(e1 = event[:foo]) + obj.call(e2 = event[:bar]) + obj.call(e3 = event[:baz]) + obj.call(event[:buz]) + unless obj.event_log == [e1, e2, e3] + raise "#{klass}: #{obj.event_log.inspect}" + end +end diff --git a/benchmark/bm_dispatch_send.rb b/benchmark/bm_dispatch_send.rb new file mode 100644 index 00000000..f1b04af1 --- /dev/null +++ b/benchmark/bm_dispatch_send.rb @@ -0,0 +1,38 @@ +class SendDispatch + attr_reader :event_log + + def initialize + @event_log = [] + end + + def call(event) + handler_name = "handle_#{event.name}" + __send__(handler_name, event) if respond_to?(handler_name) + end + + def handle_foo(event) + event_log << event + end + + def handle_bar(event) + event_log << event + end + + def handle_baz(event) + event_log << event + end +end + +klass = SendDispatch +event = Struct.new(:name, :source, :args) + +100_000.times do + obj = klass.new + obj.call(e1 = event[:foo]) + obj.call(e2 = event[:bar]) + obj.call(e3 = event[:baz]) + obj.call(event[:buz]) + unless obj.event_log == [e1, e2, e3] + raise "#{klass}: #{obj.event_log.inspect}" + end +end diff --git a/benchmark/bm_dispatch_send_table.rb b/benchmark/bm_dispatch_send_table.rb new file mode 100644 index 00000000..3be3777b --- /dev/null +++ b/benchmark/bm_dispatch_send_table.rb @@ -0,0 +1,57 @@ +class SendTableDispatch + attr_reader :event_log + + def initialize + @event_log = [] + end + + def self.method_added_cheat(method_name) + if method_name.to_s =~ /^handle_(.+)$/ + handler_methods[$1.to_sym] = method_name.to_sym + end + # Cheating here, because Opal does not support method_added hook yet + # Uncomment the super below when it does: + # super + end + + def self.handler_methods + @handler_methods ||= {} + end + + def call(event) + if (handler_method = self.class.handler_methods[event.name]) + __send__(handler_method, event) + end + end + + def handle_foo(event) + event_log << event + end + + def handle_bar(event) + event_log << event + end + + def handle_baz(event) + event_log << event + end +end + +klass = SendTableDispatch +event = Struct.new(:name, :source, :args) + +# Cheating here, because Opal does not support method_added hook yet +klass.method_added_cheat(:handle_foo) +klass.method_added_cheat(:handle_bar) +klass.method_added_cheat(:handle_baz) + +100_000.times do + obj = klass.new + obj.call(e1 = event[:foo]) + obj.call(e2 = event[:bar]) + obj.call(e3 = event[:baz]) + obj.call(event[:buz]) + unless obj.event_log == [e1, e2, e3] + raise "#{klass}: #{obj.event_log.inspect}" + end +end diff --git a/benchmark/bm_hash_assoc_object.rb b/benchmark/bm_hash_assoc_object.rb new file mode 100644 index 00000000..f0540f0f --- /dev/null +++ b/benchmark/bm_hash_assoc_object.rb @@ -0,0 +1,11 @@ +h = {} +a = [] + +10_000.times do |i| + a[i] = Object.new + h[a[i]] = nil +end + +10_000.times do |i| + k, v = h.assoc(a[i]) +end diff --git a/benchmark/bm_hash_assoc_string.rb b/benchmark/bm_hash_assoc_string.rb new file mode 100644 index 00000000..ffbbab9e --- /dev/null +++ b/benchmark/bm_hash_assoc_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +10_000.times do |i| + k, v = h.assoc(i.to_s) +end diff --git a/benchmark/bm_hash_clone_object.rb b/benchmark/bm_hash_clone_object.rb new file mode 100644 index 00000000..875e5f28 --- /dev/null +++ b/benchmark/bm_hash_clone_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +100.times do |i| + h.clone +end diff --git a/benchmark/bm_hash_clone_string.rb b/benchmark/bm_hash_clone_string.rb new file mode 100644 index 00000000..53c26410 --- /dev/null +++ b/benchmark/bm_hash_clone_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +100.times do |i| + h.clone +end diff --git a/benchmark/bm_hash_delete_object.rb b/benchmark/bm_hash_delete_object.rb new file mode 100644 index 00000000..82fd5735 --- /dev/null +++ b/benchmark/bm_hash_delete_object.rb @@ -0,0 +1,11 @@ +h = {} +a = [] + +10_000.times do |i| + a[i] = Object.new + h[a[i]] = nil +end + +10_000.times do |i| + h.delete(a[i]) +end diff --git a/benchmark/bm_hash_delete_string.rb b/benchmark/bm_hash_delete_string.rb new file mode 100644 index 00000000..a404e4ee --- /dev/null +++ b/benchmark/bm_hash_delete_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +10_000.times do |i| + h.delete(i.to_s) +end diff --git a/benchmark/bm_hash_each_key_object.rb b/benchmark/bm_hash_each_key_object.rb new file mode 100644 index 00000000..57a6bf69 --- /dev/null +++ b/benchmark/bm_hash_each_key_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do |i| + h.each_key{|k| nil} +end diff --git a/benchmark/bm_hash_each_key_string.rb b/benchmark/bm_hash_each_key_string.rb new file mode 100644 index 00000000..e5f2213a --- /dev/null +++ b/benchmark/bm_hash_each_key_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do |i| + h.each_key{|k| nil} +end diff --git a/benchmark/bm_hash_each_object.rb b/benchmark/bm_hash_each_object.rb new file mode 100644 index 00000000..0c449890 --- /dev/null +++ b/benchmark/bm_hash_each_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do |i| + h.each{|k, v| nil} +end diff --git a/benchmark/bm_hash_each_string.rb b/benchmark/bm_hash_each_string.rb new file mode 100644 index 00000000..dfaf35bd --- /dev/null +++ b/benchmark/bm_hash_each_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do |i| + h.each{|k, v| nil} +end diff --git a/benchmark/bm_hash_each_value_object.rb b/benchmark/bm_hash_each_value_object.rb new file mode 100644 index 00000000..eb5d27f7 --- /dev/null +++ b/benchmark/bm_hash_each_value_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do |i| + h.each_value{|v| nil} +end diff --git a/benchmark/bm_hash_each_value_string.rb b/benchmark/bm_hash_each_value_string.rb new file mode 100644 index 00000000..a05112ca --- /dev/null +++ b/benchmark/bm_hash_each_value_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do |i| + h.each_value{|v| nil} +end diff --git a/benchmark/bm_hash_element_reference_object.rb b/benchmark/bm_hash_element_reference_object.rb new file mode 100644 index 00000000..2c40f315 --- /dev/null +++ b/benchmark/bm_hash_element_reference_object.rb @@ -0,0 +1,11 @@ +h = {} +a = [] + +10_000.times do |i| + a[i] = Object.new + h[a[i]] = nil +end + +10_000.times do |i| + h[a[i]] +end diff --git a/benchmark/bm_hash_element_reference_string.rb b/benchmark/bm_hash_element_reference_string.rb new file mode 100644 index 00000000..6fc73ea2 --- /dev/null +++ b/benchmark/bm_hash_element_reference_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +10_000.times do |i| + h[i.to_s] +end diff --git a/benchmark/bm_hash_element_set_object.rb b/benchmark/bm_hash_element_set_object.rb new file mode 100644 index 00000000..c1d778c0 --- /dev/null +++ b/benchmark/bm_hash_element_set_object.rb @@ -0,0 +1,5 @@ +h = {} + +100_000.times do |i| + h[Object.new] = nil +end diff --git a/benchmark/bm_hash_element_set_string.rb b/benchmark/bm_hash_element_set_string.rb new file mode 100644 index 00000000..0eb03ddc --- /dev/null +++ b/benchmark/bm_hash_element_set_string.rb @@ -0,0 +1,5 @@ +h = {} + +100_000.times do |i| + h[i.to_s] = nil +end diff --git a/benchmark/bm_hash_equal_value_object.rb b/benchmark/bm_hash_equal_value_object.rb new file mode 100644 index 00000000..3bbae2a5 --- /dev/null +++ b/benchmark/bm_hash_equal_value_object.rb @@ -0,0 +1,14 @@ +h1 = {} +h2 = {} + +a = [] + +10_000.times do |i| + a[i] = Object.new + h1[a[i]] = nil + h2[a[i]] = nil +end + +1_000.times do + h1 == h2 +end diff --git a/benchmark/bm_hash_equal_value_string.rb b/benchmark/bm_hash_equal_value_string.rb new file mode 100644 index 00000000..c846aee6 --- /dev/null +++ b/benchmark/bm_hash_equal_value_string.rb @@ -0,0 +1,11 @@ +h1 = {} +h2 = {} + +10_000.times do |i| + h1[i.to_s] = nil + h2[i.to_s] = nil +end + +1_000.times do + h1 == h2 +end diff --git a/benchmark/bm_hash_fetch_object.rb b/benchmark/bm_hash_fetch_object.rb new file mode 100644 index 00000000..5283b13a --- /dev/null +++ b/benchmark/bm_hash_fetch_object.rb @@ -0,0 +1,11 @@ +h = {} +a = [] + +10_000.times do |i| + a[i] = Object.new + h[a[i]] = nil +end + +1_000.times do |i| + h.fetch(a[i]) +end diff --git a/benchmark/bm_hash_fetch_string.rb b/benchmark/bm_hash_fetch_string.rb new file mode 100644 index 00000000..42b2a69c --- /dev/null +++ b/benchmark/bm_hash_fetch_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do |i| + h.fetch(i.to_s) +end diff --git a/benchmark/bm_hash_flatten_object.rb b/benchmark/bm_hash_flatten_object.rb new file mode 100644 index 00000000..e4b72cf3 --- /dev/null +++ b/benchmark/bm_hash_flatten_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do + h.flatten +end diff --git a/benchmark/bm_hash_flatten_string.rb b/benchmark/bm_hash_flatten_string.rb new file mode 100644 index 00000000..403497f6 --- /dev/null +++ b/benchmark/bm_hash_flatten_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do + h.flatten +end diff --git a/benchmark/bm_hash_has_key_object.rb b/benchmark/bm_hash_has_key_object.rb new file mode 100644 index 00000000..7b46287d --- /dev/null +++ b/benchmark/bm_hash_has_key_object.rb @@ -0,0 +1,11 @@ +h = {} +a = [] + +10_000.times do |i| + a[i] = Object.new + h[a[i]] = nil +end + +10_000.times do |i| + h.has_key?(a[i]) +end diff --git a/benchmark/bm_hash_has_key_string.rb b/benchmark/bm_hash_has_key_string.rb new file mode 100644 index 00000000..d0f08b94 --- /dev/null +++ b/benchmark/bm_hash_has_key_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +10_000.times do |i| + h.has_key?(i.to_s) +end diff --git a/benchmark/bm_hash_has_value_object.rb b/benchmark/bm_hash_has_value_object.rb new file mode 100644 index 00000000..8f5b27e7 --- /dev/null +++ b/benchmark/bm_hash_has_value_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i * 2 +end + +1_000.times do |i| + h.has_value?(i * 2) +end diff --git a/benchmark/bm_hash_has_value_string.rb b/benchmark/bm_hash_has_value_string.rb new file mode 100644 index 00000000..b7fa26ec --- /dev/null +++ b/benchmark/bm_hash_has_value_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i * 2 +end + +1_000.times do |i| + h.has_value?(i * 2) +end diff --git a/benchmark/bm_hash_hash_object.rb b/benchmark/bm_hash_hash_object.rb new file mode 100644 index 00000000..c56df74f --- /dev/null +++ b/benchmark/bm_hash_hash_object.rb @@ -0,0 +1,9 @@ +h = {} + +1_000.times do |i| + h[Object.new] = nil +end + +100.times do |i| + h.hash +end diff --git a/benchmark/bm_hash_hash_string.rb b/benchmark/bm_hash_hash_string.rb new file mode 100644 index 00000000..27fb2f52 --- /dev/null +++ b/benchmark/bm_hash_hash_string.rb @@ -0,0 +1,9 @@ +h = {} + +1_000.times do |i| + h[i.to_s] = nil +end + +100.times do |i| + h.hash +end diff --git a/benchmark/bm_hash_inspect_object.rb b/benchmark/bm_hash_inspect_object.rb new file mode 100644 index 00000000..be50b056 --- /dev/null +++ b/benchmark/bm_hash_inspect_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +100.times do + h.inspect +end diff --git a/benchmark/bm_hash_inspect_string.rb b/benchmark/bm_hash_inspect_string.rb new file mode 100644 index 00000000..eb38a692 --- /dev/null +++ b/benchmark/bm_hash_inspect_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +100.times do + h.inspect +end diff --git a/benchmark/bm_hash_invert_object.rb b/benchmark/bm_hash_invert_object.rb new file mode 100644 index 00000000..6467771c --- /dev/null +++ b/benchmark/bm_hash_invert_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +100.times do + h.invert +end diff --git a/benchmark/bm_hash_invert_string.rb b/benchmark/bm_hash_invert_string.rb new file mode 100644 index 00000000..67ef045a --- /dev/null +++ b/benchmark/bm_hash_invert_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +100.times do + h.invert +end diff --git a/benchmark/bm_hash_keep_if_object.rb b/benchmark/bm_hash_keep_if_object.rb new file mode 100644 index 00000000..318bf19a --- /dev/null +++ b/benchmark/bm_hash_keep_if_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +1_000.times do + h.keep_if{|k, v| v % 2 == 0} +end diff --git a/benchmark/bm_hash_keep_if_string.rb b/benchmark/bm_hash_keep_if_string.rb new file mode 100644 index 00000000..566bb179 --- /dev/null +++ b/benchmark/bm_hash_keep_if_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +1_000.times do + h.keep_if{|k, v| v % 2 == 0} +end diff --git a/benchmark/bm_hash_key_object.rb b/benchmark/bm_hash_key_object.rb new file mode 100644 index 00000000..028a8837 --- /dev/null +++ b/benchmark/bm_hash_key_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +1_000.times do |i| + h.key(i) +end diff --git a/benchmark/bm_hash_key_string.rb b/benchmark/bm_hash_key_string.rb new file mode 100644 index 00000000..030969dc --- /dev/null +++ b/benchmark/bm_hash_key_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +1_000.times do |i| + h.key(i) +end diff --git a/benchmark/bm_hash_keys_object.rb b/benchmark/bm_hash_keys_object.rb new file mode 100644 index 00000000..a2c6158d --- /dev/null +++ b/benchmark/bm_hash_keys_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +5_000.times do + h.keys +end diff --git a/benchmark/bm_hash_keys_string.rb b/benchmark/bm_hash_keys_string.rb new file mode 100644 index 00000000..f21b2774 --- /dev/null +++ b/benchmark/bm_hash_keys_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +5_000.times do + h.keys +end diff --git a/benchmark/bm_hash_literal_mixed_large.rb b/benchmark/bm_hash_literal_mixed_large.rb new file mode 100644 index 00000000..2cc991ca --- /dev/null +++ b/benchmark/bm_hash_literal_mixed_large.rb @@ -0,0 +1,3 @@ +1000.times do + h = {Object.new => '0', '1' => '1', Object.new => '2', '3' => '3', Object.new => '4', '5' => '5', Object.new => '6', '7' => '7', Object.new => '8', '9' => '9', Object.new => '10', '11' => '11', Object.new => '12', '13' => '13', Object.new => '14', '15' => '15', Object.new => '16', '17' => '17', Object.new => '18', '19' => '19', Object.new => '20', '21' => '21', Object.new => '22', '23' => '23', Object.new => '24', '25' => '25', Object.new => '26', '27' => '27', Object.new => '28', '29' => '29', Object.new => '30', '31' => '31', Object.new => '32', '33' => '33', Object.new => '34', '35' => '35', Object.new => '36', '37' => '37', Object.new => '38', '39' => '39', Object.new => '40', '41' => '41', Object.new => '42', '43' => '43', Object.new => '44', '45' => '45', Object.new => '46', '47' => '47', Object.new => '48', '49' => '49', Object.new => '50', '51' => '51', Object.new => '52', '53' => '53', Object.new => '54', '55' => '55', Object.new => '56', '57' => '57', Object.new => '58', '59' => '59', Object.new => '60', '61' => '61', Object.new => '62', '63' => '63', Object.new => '64', '65' => '65', Object.new => '66', '67' => '67', Object.new => '68', '69' => '69', Object.new => '70', '71' => '71', Object.new => '72', '73' => '73', Object.new => '74', '75' => '75', Object.new => '76', '77' => '77', Object.new => '78', '79' => '79', Object.new => '80', '81' => '81', Object.new => '82', '83' => '83', Object.new => '84', '85' => '85', Object.new => '86', '87' => '87', Object.new => '88', '89' => '89', Object.new => '90', '91' => '91', Object.new => '92', '93' => '93', Object.new => '94', '95' => '95', Object.new => '96', '97' => '97', Object.new => '98', '99' => '99', Object.new => '100', '101' => '101', Object.new => '102', '103' => '103', Object.new => '104', '105' => '105', Object.new => '106', '107' => '107', Object.new => '108', '109' => '109', Object.new => '110', '111' => '111', Object.new => '112', '113' => '113', Object.new => '114', '115' => '115', Object.new => '116', '117' => '117', Object.new => '118', '119' => '119', Object.new => '120', '121' => '121', Object.new => '122', '123' => '123', Object.new => '124', '125' => '125', Object.new => '126', '127' => '127', Object.new => '128', '129' => '129', Object.new => '130', '131' => '131', Object.new => '132', '133' => '133', Object.new => '134', '135' => '135', Object.new => '136', '137' => '137', Object.new => '138', '139' => '139', Object.new => '140', '141' => '141', Object.new => '142', '143' => '143', Object.new => '144', '145' => '145', Object.new => '146', '147' => '147', Object.new => '148', '149' => '149', Object.new => '150', '151' => '151', Object.new => '152', '153' => '153', Object.new => '154', '155' => '155', Object.new => '156', '157' => '157', Object.new => '158', '159' => '159', Object.new => '160', '161' => '161', Object.new => '162', '163' => '163', Object.new => '164', '165' => '165', Object.new => '166', '167' => '167', Object.new => '168', '169' => '169', Object.new => '170', '171' => '171', Object.new => '172', '173' => '173', Object.new => '174', '175' => '175', Object.new => '176', '177' => '177', Object.new => '178', '179' => '179', Object.new => '180', '181' => '181', Object.new => '182', '183' => '183', Object.new => '184', '185' => '185', Object.new => '186', '187' => '187', Object.new => '188', '189' => '189', Object.new => '190', '191' => '191', Object.new => '192', '193' => '193', Object.new => '194', '195' => '195', Object.new => '196', '197' => '197', Object.new => '198', '199' => '199', Object.new => '200', '201' => '201', Object.new => '202', '203' => '203', Object.new => '204', '205' => '205', Object.new => '206', '207' => '207', Object.new => '208', '209' => '209', Object.new => '210', '211' => '211', Object.new => '212', '213' => '213', Object.new => '214', '215' => '215', Object.new => '216', '217' => '217', Object.new => '218', '219' => '219', Object.new => '220', '221' => '221', Object.new => '222', '223' => '223', Object.new => '224', '225' => '225', Object.new => '226', '227' => '227', Object.new => '228', '229' => '229', Object.new => '230', '231' => '231', Object.new => '232', '233' => '233', Object.new => '234', '235' => '235', Object.new => '236', '237' => '237', Object.new => '238', '239' => '239', Object.new => '240', '241' => '241', Object.new => '242', '243' => '243', Object.new => '244', '245' => '245', Object.new => '246', '247' => '247', Object.new => '248', '249' => '249', Object.new => '250', '251' => '251', Object.new => '252', '253' => '253', Object.new => '254', '255' => '255', Object.new => '256', '257' => '257', Object.new => '258', '259' => '259', Object.new => '260', '261' => '261', Object.new => '262', '263' => '263', Object.new => '264', '265' => '265', Object.new => '266', '267' => '267', Object.new => '268', '269' => '269', Object.new => '270', '271' => '271', Object.new => '272', '273' => '273', Object.new => '274', '275' => '275', Object.new => '276', '277' => '277', Object.new => '278', '279' => '279', Object.new => '280', '281' => '281', Object.new => '282', '283' => '283', Object.new => '284', '285' => '285', Object.new => '286', '287' => '287', Object.new => '288', '289' => '289', Object.new => '290', '291' => '291', Object.new => '292', '293' => '293', Object.new => '294', '295' => '295', Object.new => '296', '297' => '297', Object.new => '298', '299' => '299', Object.new => '300', '301' => '301', Object.new => '302', '303' => '303', Object.new => '304', '305' => '305', Object.new => '306', '307' => '307', Object.new => '308', '309' => '309', Object.new => '310', '311' => '311', Object.new => '312', '313' => '313', Object.new => '314', '315' => '315', Object.new => '316', '317' => '317', Object.new => '318', '319' => '319', Object.new => '320', '321' => '321', Object.new => '322', '323' => '323', Object.new => '324', '325' => '325', Object.new => '326', '327' => '327', Object.new => '328', '329' => '329', Object.new => '330', '331' => '331', Object.new => '332', '333' => '333', Object.new => '334', '335' => '335', Object.new => '336', '337' => '337', Object.new => '338', '339' => '339', Object.new => '340', '341' => '341', Object.new => '342', '343' => '343', Object.new => '344', '345' => '345', Object.new => '346', '347' => '347', Object.new => '348', '349' => '349', Object.new => '350', '351' => '351', Object.new => '352', '353' => '353', Object.new => '354', '355' => '355', Object.new => '356', '357' => '357', Object.new => '358', '359' => '359', Object.new => '360', '361' => '361', Object.new => '362', '363' => '363', Object.new => '364', '365' => '365', Object.new => '366', '367' => '367', Object.new => '368', '369' => '369', Object.new => '370', '371' => '371', Object.new => '372', '373' => '373', Object.new => '374', '375' => '375', Object.new => '376', '377' => '377', Object.new => '378', '379' => '379', Object.new => '380', '381' => '381', Object.new => '382', '383' => '383', Object.new => '384', '385' => '385', Object.new => '386', '387' => '387', Object.new => '388', '389' => '389', Object.new => '390', '391' => '391', Object.new => '392', '393' => '393', Object.new => '394', '395' => '395', Object.new => '396', '397' => '397', Object.new => '398', '399' => '399', Object.new => '400', '401' => '401', Object.new => '402', '403' => '403', Object.new => '404', '405' => '405', Object.new => '406', '407' => '407', Object.new => '408', '409' => '409', Object.new => '410', '411' => '411', Object.new => '412', '413' => '413', Object.new => '414', '415' => '415', Object.new => '416', '417' => '417', Object.new => '418', '419' => '419', Object.new => '420', '421' => '421', Object.new => '422', '423' => '423', Object.new => '424', '425' => '425', Object.new => '426', '427' => '427', Object.new => '428', '429' => '429', Object.new => '430', '431' => '431', Object.new => '432', '433' => '433', Object.new => '434', '435' => '435', Object.new => '436', '437' => '437', Object.new => '438', '439' => '439', Object.new => '440', '441' => '441', Object.new => '442', '443' => '443', Object.new => '444', '445' => '445', Object.new => '446', '447' => '447', Object.new => '448', '449' => '449', Object.new => '450', '451' => '451', Object.new => '452', '453' => '453', Object.new => '454', '455' => '455', Object.new => '456', '457' => '457', Object.new => '458', '459' => '459', Object.new => '460', '461' => '461', Object.new => '462', '463' => '463', Object.new => '464', '465' => '465', Object.new => '466', '467' => '467', Object.new => '468', '469' => '469', Object.new => '470', '471' => '471', Object.new => '472', '473' => '473', Object.new => '474', '475' => '475', Object.new => '476', '477' => '477', Object.new => '478', '479' => '479', Object.new => '480', '481' => '481', Object.new => '482', '483' => '483', Object.new => '484', '485' => '485', Object.new => '486', '487' => '487', Object.new => '488', '489' => '489', Object.new => '490', '491' => '491', Object.new => '492', '493' => '493', Object.new => '494', '495' => '495', Object.new => '496', '497' => '497', Object.new => '498', '499' => '499', Object.new => '500', '501' => '501', Object.new => '502', '503' => '503', Object.new => '504', '505' => '505', Object.new => '506', '507' => '507', Object.new => '508', '509' => '509', Object.new => '510', '511' => '511', Object.new => '512', '513' => '513', Object.new => '514', '515' => '515', Object.new => '516', '517' => '517', Object.new => '518', '519' => '519', Object.new => '520', '521' => '521', Object.new => '522', '523' => '523', Object.new => '524', '525' => '525', Object.new => '526', '527' => '527', Object.new => '528', '529' => '529', Object.new => '530', '531' => '531', Object.new => '532', '533' => '533', Object.new => '534', '535' => '535', Object.new => '536', '537' => '537', Object.new => '538', '539' => '539', Object.new => '540', '541' => '541', Object.new => '542', '543' => '543', Object.new => '544', '545' => '545', Object.new => '546', '547' => '547', Object.new => '548', '549' => '549', Object.new => '550', '551' => '551', Object.new => '552', '553' => '553', Object.new => '554', '555' => '555', Object.new => '556', '557' => '557', Object.new => '558', '559' => '559', Object.new => '560', '561' => '561', Object.new => '562', '563' => '563', Object.new => '564', '565' => '565', Object.new => '566', '567' => '567', Object.new => '568', '569' => '569', Object.new => '570', '571' => '571', Object.new => '572', '573' => '573', Object.new => '574', '575' => '575', Object.new => '576', '577' => '577', Object.new => '578', '579' => '579', Object.new => '580', '581' => '581', Object.new => '582', '583' => '583', Object.new => '584', '585' => '585', Object.new => '586', '587' => '587', Object.new => '588', '589' => '589', Object.new => '590', '591' => '591', Object.new => '592', '593' => '593', Object.new => '594', '595' => '595', Object.new => '596', '597' => '597', Object.new => '598', '599' => '599', Object.new => '600', '601' => '601', Object.new => '602', '603' => '603', Object.new => '604', '605' => '605', Object.new => '606', '607' => '607', Object.new => '608', '609' => '609', Object.new => '610', '611' => '611', Object.new => '612', '613' => '613', Object.new => '614', '615' => '615', Object.new => '616', '617' => '617', Object.new => '618', '619' => '619', Object.new => '620', '621' => '621', Object.new => '622', '623' => '623', Object.new => '624', '625' => '625', Object.new => '626', '627' => '627', Object.new => '628', '629' => '629', Object.new => '630', '631' => '631', Object.new => '632', '633' => '633', Object.new => '634', '635' => '635', Object.new => '636', '637' => '637', Object.new => '638', '639' => '639', Object.new => '640', '641' => '641', Object.new => '642', '643' => '643', Object.new => '644', '645' => '645', Object.new => '646', '647' => '647', Object.new => '648', '649' => '649', Object.new => '650', '651' => '651', Object.new => '652', '653' => '653', Object.new => '654', '655' => '655', Object.new => '656', '657' => '657', Object.new => '658', '659' => '659', Object.new => '660', '661' => '661', Object.new => '662', '663' => '663', Object.new => '664', '665' => '665', Object.new => '666', '667' => '667', Object.new => '668', '669' => '669', Object.new => '670', '671' => '671', Object.new => '672', '673' => '673', Object.new => '674', '675' => '675', Object.new => '676', '677' => '677', Object.new => '678', '679' => '679', Object.new => '680', '681' => '681', Object.new => '682', '683' => '683', Object.new => '684', '685' => '685', Object.new => '686', '687' => '687', Object.new => '688', '689' => '689', Object.new => '690', '691' => '691', Object.new => '692', '693' => '693', Object.new => '694', '695' => '695', Object.new => '696', '697' => '697', Object.new => '698', '699' => '699', Object.new => '700', '701' => '701', Object.new => '702', '703' => '703', Object.new => '704', '705' => '705', Object.new => '706', '707' => '707', Object.new => '708', '709' => '709', Object.new => '710', '711' => '711', Object.new => '712', '713' => '713', Object.new => '714', '715' => '715', Object.new => '716', '717' => '717', Object.new => '718', '719' => '719', Object.new => '720', '721' => '721', Object.new => '722', '723' => '723', Object.new => '724', '725' => '725', Object.new => '726', '727' => '727', Object.new => '728', '729' => '729', Object.new => '730', '731' => '731', Object.new => '732', '733' => '733', Object.new => '734', '735' => '735', Object.new => '736', '737' => '737', Object.new => '738', '739' => '739', Object.new => '740', '741' => '741', Object.new => '742', '743' => '743', Object.new => '744', '745' => '745', Object.new => '746', '747' => '747', Object.new => '748', '749' => '749', Object.new => '750', '751' => '751', Object.new => '752', '753' => '753', Object.new => '754', '755' => '755', Object.new => '756', '757' => '757', Object.new => '758', '759' => '759', Object.new => '760', '761' => '761', Object.new => '762', '763' => '763', Object.new => '764', '765' => '765', Object.new => '766', '767' => '767', Object.new => '768', '769' => '769', Object.new => '770', '771' => '771', Object.new => '772', '773' => '773', Object.new => '774', '775' => '775', Object.new => '776', '777' => '777', Object.new => '778', '779' => '779', Object.new => '780', '781' => '781', Object.new => '782', '783' => '783', Object.new => '784', '785' => '785', Object.new => '786', '787' => '787', Object.new => '788', '789' => '789', Object.new => '790', '791' => '791', Object.new => '792', '793' => '793', Object.new => '794', '795' => '795', Object.new => '796', '797' => '797', Object.new => '798', '799' => '799', Object.new => '800', '801' => '801', Object.new => '802', '803' => '803', Object.new => '804', '805' => '805', Object.new => '806', '807' => '807', Object.new => '808', '809' => '809', Object.new => '810', '811' => '811', Object.new => '812', '813' => '813', Object.new => '814', '815' => '815', Object.new => '816', '817' => '817', Object.new => '818', '819' => '819', Object.new => '820', '821' => '821', Object.new => '822', '823' => '823', Object.new => '824', '825' => '825', Object.new => '826', '827' => '827', Object.new => '828', '829' => '829', Object.new => '830', '831' => '831', Object.new => '832', '833' => '833', Object.new => '834', '835' => '835', Object.new => '836', '837' => '837', Object.new => '838', '839' => '839', Object.new => '840', '841' => '841', Object.new => '842', '843' => '843', Object.new => '844', '845' => '845', Object.new => '846', '847' => '847', Object.new => '848', '849' => '849', Object.new => '850', '851' => '851', Object.new => '852', '853' => '853', Object.new => '854', '855' => '855', Object.new => '856', '857' => '857', Object.new => '858', '859' => '859', Object.new => '860', '861' => '861', Object.new => '862', '863' => '863', Object.new => '864', '865' => '865', Object.new => '866', '867' => '867', Object.new => '868', '869' => '869', Object.new => '870', '871' => '871', Object.new => '872', '873' => '873', Object.new => '874', '875' => '875', Object.new => '876', '877' => '877', Object.new => '878', '879' => '879', Object.new => '880', '881' => '881', Object.new => '882', '883' => '883', Object.new => '884', '885' => '885', Object.new => '886', '887' => '887', Object.new => '888', '889' => '889', Object.new => '890', '891' => '891', Object.new => '892', '893' => '893', Object.new => '894', '895' => '895', Object.new => '896', '897' => '897', Object.new => '898', '899' => '899', Object.new => '900', '901' => '901', Object.new => '902', '903' => '903', Object.new => '904', '905' => '905', Object.new => '906', '907' => '907', Object.new => '908', '909' => '909', Object.new => '910', '911' => '911', Object.new => '912', '913' => '913', Object.new => '914', '915' => '915', Object.new => '916', '917' => '917', Object.new => '918', '919' => '919', Object.new => '920', '921' => '921', Object.new => '922', '923' => '923', Object.new => '924', '925' => '925', Object.new => '926', '927' => '927', Object.new => '928', '929' => '929', Object.new => '930', '931' => '931', Object.new => '932', '933' => '933', Object.new => '934', '935' => '935', Object.new => '936', '937' => '937', Object.new => '938', '939' => '939', Object.new => '940', '941' => '941', Object.new => '942', '943' => '943', Object.new => '944', '945' => '945', Object.new => '946', '947' => '947', Object.new => '948', '949' => '949', Object.new => '950', '951' => '951', Object.new => '952', '953' => '953', Object.new => '954', '955' => '955', Object.new => '956', '957' => '957', Object.new => '958', '959' => '959', Object.new => '960', '961' => '961', Object.new => '962', '963' => '963', Object.new => '964', '965' => '965', Object.new => '966', '967' => '967', Object.new => '968', '969' => '969', Object.new => '970', '971' => '971', Object.new => '972', '973' => '973', Object.new => '974', '975' => '975', Object.new => '976', '977' => '977', Object.new => '978', '979' => '979', Object.new => '980', '981' => '981', Object.new => '982', '983' => '983', Object.new => '984', '985' => '985', Object.new => '986', '987' => '987', Object.new => '988', '989' => '989', Object.new => '990', '991' => '991', Object.new => '992', '993' => '993', Object.new => '994', '995' => '995', Object.new => '996', '997' => '997', Object.new => '998', '999' => '999'} +end diff --git a/benchmark/bm_hash_literal_mixed_small.rb b/benchmark/bm_hash_literal_mixed_small.rb new file mode 100644 index 00000000..84f6af9a --- /dev/null +++ b/benchmark/bm_hash_literal_mixed_small.rb @@ -0,0 +1,3 @@ +10_000.times do + h = {'a' => 'b', Object.new => 'd', 'e' => 'f', Object.new => 'h', 'i' => 'j', Object.new => 'l', 'm' => 'n', Object.new => 'p'} +end diff --git a/benchmark/bm_hash_literal_object_large.rb b/benchmark/bm_hash_literal_object_large.rb new file mode 100644 index 00000000..9270e9bb --- /dev/null +++ b/benchmark/bm_hash_literal_object_large.rb @@ -0,0 +1,4 @@ +1000.times do + h = {Object.new => '0', Object.new => '1', Object.new => '2', Object.new => '3', Object.new => '4', Object.new => '5', Object.new => '6', Object.new => '7', Object.new => '8', Object.new => '9', Object.new => '10', Object.new => '11', Object.new => '12', Object.new => '13', Object.new => '14', Object.new => '15', Object.new => '16', Object.new => '17', Object.new => '18', Object.new => '19', Object.new => '20', Object.new => '21', Object.new => '22', Object.new => '23', Object.new => '24', Object.new => '25', Object.new => '26', Object.new => '27', Object.new => '28', Object.new => '29', Object.new => '30', Object.new => '31', Object.new => '32', Object.new => '33', Object.new => '34', Object.new => '35', Object.new => '36', Object.new => '37', Object.new => '38', Object.new => '39', Object.new => '40', Object.new => '41', Object.new => '42', Object.new => '43', Object.new => '44', Object.new => '45', Object.new => '46', Object.new => '47', Object.new => '48', Object.new => '49', Object.new => '50', Object.new => '51', Object.new => '52', Object.new => '53', Object.new => '54', Object.new => '55', Object.new => '56', Object.new => '57', Object.new => '58', Object.new => '59', Object.new => '60', Object.new => '61', Object.new => '62', Object.new => '63', Object.new => '64', Object.new => '65', Object.new => '66', Object.new => '67', Object.new => '68', Object.new => '69', Object.new => '70', Object.new => '71', Object.new => '72', Object.new => '73', Object.new => '74', Object.new => '75', Object.new => '76', Object.new => '77', Object.new => '78', Object.new => '79', Object.new => '80', Object.new => '81', Object.new => '82', Object.new => '83', Object.new => '84', Object.new => '85', Object.new => '86', Object.new => '87', Object.new => '88', Object.new => '89', Object.new => '90', Object.new => '91', Object.new => '92', Object.new => '93', Object.new => '94', Object.new => '95', Object.new => '96', Object.new => '97', Object.new => '98', Object.new => '99', Object.new => '100', Object.new => '101', Object.new => '102', Object.new => '103', Object.new => '104', Object.new => '105', Object.new => '106', Object.new => '107', Object.new => '108', Object.new => '109', Object.new => '110', Object.new => '111', Object.new => '112', Object.new => '113', Object.new => '114', Object.new => '115', Object.new => '116', Object.new => '117', Object.new => '118', Object.new => '119', Object.new => '120', Object.new => '121', Object.new => '122', Object.new => '123', Object.new => '124', Object.new => '125', Object.new => '126', Object.new => '127', Object.new => '128', Object.new => '129', Object.new => '130', Object.new => '131', Object.new => '132', Object.new => '133', Object.new => '134', Object.new => '135', Object.new => '136', Object.new => '137', Object.new => '138', Object.new => '139', Object.new => '140', Object.new => '141', Object.new => '142', Object.new => '143', Object.new => '144', Object.new => '145', Object.new => '146', Object.new => '147', Object.new => '148', Object.new => '149', Object.new => '150', Object.new => '151', Object.new => '152', Object.new => '153', Object.new => '154', Object.new => '155', Object.new => '156', Object.new => '157', Object.new => '158', Object.new => '159', Object.new => '160', Object.new => '161', Object.new => '162', Object.new => '163', Object.new => '164', Object.new => '165', Object.new => '166', Object.new => '167', Object.new => '168', Object.new => '169', Object.new => '170', Object.new => '171', Object.new => '172', Object.new => '173', Object.new => '174', Object.new => '175', Object.new => '176', Object.new => '177', Object.new => '178', Object.new => '179', Object.new => '180', Object.new => '181', Object.new => '182', Object.new => '183', Object.new => '184', Object.new => '185', Object.new => '186', Object.new => '187', Object.new => '188', Object.new => '189', Object.new => '190', Object.new => '191', Object.new => '192', Object.new => '193', Object.new => '194', Object.new => '195', Object.new => '196', Object.new => '197', Object.new => '198', Object.new => '199', Object.new => '200', Object.new => '201', Object.new => '202', Object.new => '203', Object.new => '204', Object.new => '205', Object.new => '206', Object.new => '207', Object.new => '208', Object.new => '209', Object.new => '210', Object.new => '211', Object.new => '212', Object.new => '213', Object.new => '214', Object.new => '215', Object.new => '216', Object.new => '217', Object.new => '218', Object.new => '219', Object.new => '220', Object.new => '221', Object.new => '222', Object.new => '223', Object.new => '224', Object.new => '225', Object.new => '226', Object.new => '227', Object.new => '228', Object.new => '229', Object.new => '230', Object.new => '231', Object.new => '232', Object.new => '233', Object.new => '234', Object.new => '235', Object.new => '236', Object.new => '237', Object.new => '238', Object.new => '239', Object.new => '240', Object.new => '241', Object.new => '242', Object.new => '243', Object.new => '244', Object.new => '245', Object.new => '246', Object.new => '247', Object.new => '248', Object.new => '249', Object.new => '250', Object.new => '251', Object.new => '252', Object.new => '253', Object.new => '254', Object.new => '255', Object.new => '256', Object.new => '257', Object.new => '258', Object.new => '259', Object.new => '260', Object.new => '261', Object.new => '262', Object.new => '263', Object.new => '264', Object.new => '265', Object.new => '266', Object.new => '267', Object.new => '268', Object.new => '269', Object.new => '270', Object.new => '271', Object.new => '272', Object.new => '273', Object.new => '274', Object.new => '275', Object.new => '276', Object.new => '277', Object.new => '278', Object.new => '279', Object.new => '280', Object.new => '281', Object.new => '282', Object.new => '283', Object.new => '284', Object.new => '285', Object.new => '286', Object.new => '287', Object.new => '288', Object.new => '289', Object.new => '290', Object.new => '291', Object.new => '292', Object.new => '293', Object.new => '294', Object.new => '295', Object.new => '296', Object.new => '297', Object.new => '298', Object.new => '299', Object.new => '300', Object.new => '301', Object.new => '302', Object.new => '303', Object.new => '304', Object.new => '305', Object.new => '306', Object.new => '307', Object.new => '308', Object.new => '309', Object.new => '310', Object.new => '311', Object.new => '312', Object.new => '313', Object.new => '314', Object.new => '315', Object.new => '316', Object.new => '317', Object.new => '318', Object.new => '319', Object.new => '320', Object.new => '321', Object.new => '322', Object.new => '323', Object.new => '324', Object.new => '325', Object.new => '326', Object.new => '327', Object.new => '328', Object.new => '329', Object.new => '330', Object.new => '331', Object.new => '332', Object.new => '333', Object.new => '334', Object.new => '335', Object.new => '336', Object.new => '337', Object.new => '338', Object.new => '339', Object.new => '340', Object.new => '341', Object.new => '342', Object.new => '343', Object.new => '344', Object.new => '345', Object.new => '346', Object.new => '347', Object.new => '348', Object.new => '349', Object.new => '350', Object.new => '351', Object.new => '352', Object.new => '353', Object.new => '354', Object.new => '355', Object.new => '356', Object.new => '357', Object.new => '358', Object.new => '359', Object.new => '360', Object.new => '361', Object.new => '362', Object.new => '363', Object.new => '364', Object.new => '365', Object.new => '366', Object.new => '367', Object.new => '368', Object.new => '369', Object.new => '370', Object.new => '371', Object.new => '372', Object.new => '373', Object.new => '374', Object.new => '375', Object.new => '376', Object.new => '377', Object.new => '378', Object.new => '379', Object.new => '380', Object.new => '381', Object.new => '382', Object.new => '383', Object.new => '384', Object.new => '385', Object.new => '386', Object.new => '387', Object.new => '388', Object.new => '389', Object.new => '390', Object.new => '391', Object.new => '392', Object.new => '393', Object.new => '394', Object.new => '395', Object.new => '396', Object.new => '397', Object.new => '398', Object.new => '399', Object.new => '400', Object.new => '401', Object.new => '402', Object.new => '403', Object.new => '404', Object.new => '405', Object.new => '406', Object.new => '407', Object.new => '408', Object.new => '409', Object.new => '410', Object.new => '411', Object.new => '412', Object.new => '413', Object.new => '414', Object.new => '415', Object.new => '416', Object.new => '417', Object.new => '418', Object.new => '419', Object.new => '420', Object.new => '421', Object.new => '422', Object.new => '423', Object.new => '424', Object.new => '425', Object.new => '426', Object.new => '427', Object.new => '428', Object.new => '429', Object.new => '430', Object.new => '431', Object.new => '432', Object.new => '433', Object.new => '434', Object.new => '435', Object.new => '436', Object.new => '437', Object.new => '438', Object.new => '439', Object.new => '440', Object.new => '441', Object.new => '442', Object.new => '443', Object.new => '444', Object.new => '445', Object.new => '446', Object.new => '447', Object.new => '448', Object.new => '449', Object.new => '450', Object.new => '451', Object.new => '452', Object.new => '453', Object.new => '454', Object.new => '455', Object.new => '456', Object.new => '457', Object.new => '458', Object.new => '459', Object.new => '460', Object.new => '461', Object.new => '462', Object.new => '463', Object.new => '464', Object.new => '465', Object.new => '466', Object.new => '467', Object.new => '468', Object.new => '469', Object.new => '470', Object.new => '471', Object.new => '472', Object.new => '473', Object.new => '474', Object.new => '475', Object.new => '476', Object.new => '477', Object.new => '478', Object.new => '479', Object.new => '480', Object.new => '481', Object.new => '482', Object.new => '483', Object.new => '484', Object.new => '485', Object.new => '486', Object.new => '487', Object.new => '488', Object.new => '489', Object.new => '490', Object.new => '491', Object.new => '492', Object.new => '493', Object.new => '494', Object.new => '495', Object.new => '496', Object.new => '497', Object.new => '498', Object.new => '499', Object.new => '500', Object.new => '501', Object.new => '502', Object.new => '503', Object.new => '504', Object.new => '505', Object.new => '506', Object.new => '507', Object.new => '508', Object.new => '509', Object.new => '510', Object.new => '511', Object.new => '512', Object.new => '513', Object.new => '514', Object.new => '515', Object.new => '516', Object.new => '517', Object.new => '518', Object.new => '519', Object.new => '520', Object.new => '521', Object.new => '522', Object.new => '523', Object.new => '524', Object.new => '525', Object.new => '526', Object.new => '527', Object.new => '528', Object.new => '529', Object.new => '530', Object.new => '531', Object.new => '532', Object.new => '533', Object.new => '534', Object.new => '535', Object.new => '536', Object.new => '537', Object.new => '538', Object.new => '539', Object.new => '540', Object.new => '541', Object.new => '542', Object.new => '543', Object.new => '544', Object.new => '545', Object.new => '546', Object.new => '547', Object.new => '548', Object.new => '549', Object.new => '550', Object.new => '551', Object.new => '552', Object.new => '553', Object.new => '554', Object.new => '555', Object.new => '556', Object.new => '557', Object.new => '558', Object.new => '559', Object.new => '560', Object.new => '561', Object.new => '562', Object.new => '563', Object.new => '564', Object.new => '565', Object.new => '566', Object.new => '567', Object.new => '568', Object.new => '569', Object.new => '570', Object.new => '571', Object.new => '572', Object.new => '573', Object.new => '574', Object.new => '575', Object.new => '576', Object.new => '577', Object.new => '578', Object.new => '579', Object.new => '580', Object.new => '581', Object.new => '582', Object.new => '583', Object.new => '584', Object.new => '585', Object.new => '586', Object.new => '587', Object.new => '588', Object.new => '589', Object.new => '590', Object.new => '591', Object.new => '592', Object.new => '593', Object.new => '594', Object.new => '595', Object.new => '596', Object.new => '597', Object.new => '598', Object.new => '599', Object.new => '600', Object.new => '601', Object.new => '602', Object.new => '603', Object.new => '604', Object.new => '605', Object.new => '606', Object.new => '607', Object.new => '608', Object.new => '609', Object.new => '610', Object.new => '611', Object.new => '612', Object.new => '613', Object.new => '614', Object.new => '615', Object.new => '616', Object.new => '617', Object.new => '618', Object.new => '619', Object.new => '620', Object.new => '621', Object.new => '622', Object.new => '623', Object.new => '624', Object.new => '625', Object.new => '626', Object.new => '627', Object.new => '628', Object.new => '629', Object.new => '630', Object.new => '631', Object.new => '632', Object.new => '633', Object.new => '634', Object.new => '635', Object.new => '636', Object.new => '637', Object.new => '638', Object.new => '639', Object.new => '640', Object.new => '641', Object.new => '642', Object.new => '643', Object.new => '644', Object.new => '645', Object.new => '646', Object.new => '647', Object.new => '648', Object.new => '649', Object.new => '650', Object.new => '651', Object.new => '652', Object.new => '653', Object.new => '654', Object.new => '655', Object.new => '656', Object.new => '657', Object.new => '658', Object.new => '659', Object.new => '660', Object.new => '661', Object.new => '662', Object.new => '663', Object.new => '664', Object.new => '665', Object.new => '666', Object.new => '667', Object.new => '668', Object.new => '669', Object.new => '670', Object.new => '671', Object.new => '672', Object.new => '673', Object.new => '674', Object.new => '675', Object.new => '676', Object.new => '677', Object.new => '678', Object.new => '679', Object.new => '680', Object.new => '681', Object.new => '682', Object.new => '683', Object.new => '684', Object.new => '685', Object.new => '686', Object.new => '687', Object.new => '688', Object.new => '689', Object.new => '690', Object.new => '691', Object.new => '692', Object.new => '693', Object.new => '694', Object.new => '695', Object.new => '696', Object.new => '697', Object.new => '698', Object.new => '699', Object.new => '700', Object.new => '701', Object.new => '702', Object.new => '703', Object.new => '704', Object.new => '705', Object.new => '706', Object.new => '707', Object.new => '708', Object.new => '709', Object.new => '710', Object.new => '711', Object.new => '712', Object.new => '713', Object.new => '714', Object.new => '715', Object.new => '716', Object.new => '717', Object.new => '718', Object.new => '719', Object.new => '720', Object.new => '721', Object.new => '722', Object.new => '723', Object.new => '724', Object.new => '725', Object.new => '726', Object.new => '727', Object.new => '728', Object.new => '729', Object.new => '730', Object.new => '731', Object.new => '732', Object.new => '733', Object.new => '734', Object.new => '735', Object.new => '736', Object.new => '737', Object.new => '738', Object.new => '739', Object.new => '740', Object.new => '741', Object.new => '742', Object.new => '743', Object.new => '744', Object.new => '745', Object.new => '746', Object.new => '747', Object.new => '748', Object.new => '749', Object.new => '750', Object.new => '751', Object.new => '752', Object.new => '753', Object.new => '754', Object.new => '755', Object.new => '756', Object.new => '757', Object.new => '758', Object.new => '759', Object.new => '760', Object.new => '761', Object.new => '762', Object.new => '763', Object.new => '764', Object.new => '765', Object.new => '766', Object.new => '767', Object.new => '768', Object.new => '769', Object.new => '770', Object.new => '771', Object.new => '772', Object.new => '773', Object.new => '774', Object.new => '775', Object.new => '776', Object.new => '777', Object.new => '778', Object.new => '779', Object.new => '780', Object.new => '781', Object.new => '782', Object.new => '783', Object.new => '784', Object.new => '785', Object.new => '786', Object.new => '787', Object.new => '788', Object.new => '789', Object.new => '790', Object.new => '791', Object.new => '792', Object.new => '793', Object.new => '794', Object.new => '795', Object.new => '796', Object.new => '797', Object.new => '798', Object.new => '799', Object.new => '800', Object.new => '801', Object.new => '802', Object.new => '803', Object.new => '804', Object.new => '805', Object.new => '806', Object.new => '807', Object.new => '808', Object.new => '809', Object.new => '810', Object.new => '811', Object.new => '812', Object.new => '813', Object.new => '814', Object.new => '815', Object.new => '816', Object.new => '817', Object.new => '818', Object.new => '819', Object.new => '820', Object.new => '821', Object.new => '822', Object.new => '823', Object.new => '824', Object.new => '825', Object.new => '826', Object.new => '827', Object.new => '828', Object.new => '829', Object.new => '830', Object.new => '831', Object.new => '832', Object.new => '833', Object.new => '834', Object.new => '835', Object.new => '836', Object.new => '837', Object.new => '838', Object.new => '839', Object.new => '840', Object.new => '841', Object.new => '842', Object.new => '843', Object.new => '844', Object.new => '845', Object.new => '846', Object.new => '847', Object.new => '848', Object.new => '849', Object.new => '850', Object.new => '851', Object.new => '852', Object.new => '853', Object.new => '854', Object.new => '855', Object.new => '856', Object.new => '857', Object.new => '858', Object.new => '859', Object.new => '860', Object.new => '861', Object.new => '862', Object.new => '863', Object.new => '864', Object.new => '865', Object.new => '866', Object.new => '867', Object.new => '868', Object.new => '869', Object.new => '870', Object.new => '871', Object.new => '872', Object.new => '873', Object.new => '874', Object.new => '875', Object.new => '876', Object.new => '877', Object.new => '878', Object.new => '879', Object.new => '880', Object.new => '881', Object.new => '882', Object.new => '883', Object.new => '884', Object.new => '885', Object.new => '886', Object.new => '887', Object.new => '888', Object.new => '889', Object.new => '890', Object.new => '891', Object.new => '892', Object.new => '893', Object.new => '894', Object.new => '895', Object.new => '896', Object.new => '897', Object.new => '898', Object.new => '899', Object.new => '900', Object.new => '901', Object.new => '902', Object.new => '903', Object.new => '904', Object.new => '905', Object.new => '906', Object.new => '907', Object.new => '908', Object.new => '909', Object.new => '910', Object.new => '911', Object.new => '912', Object.new => '913', Object.new => '914', Object.new => '915', Object.new => '916', Object.new => '917', Object.new => '918', Object.new => '919', Object.new => '920', Object.new => '921', Object.new => '922', Object.new => '923', Object.new => '924', Object.new => '925', Object.new => '926', Object.new => '927', Object.new => '928', Object.new => '929', Object.new => '930', Object.new => '931', Object.new => '932', Object.new => '933', Object.new => '934', Object.new => '935', Object.new => '936', Object.new => '937', Object.new => '938', Object.new => '939', Object.new => '940', Object.new => '941', Object.new => '942', Object.new => '943', Object.new => '944', Object.new => '945', Object.new => '946', Object.new => '947', Object.new => '948', Object.new => '949', Object.new => '950', Object.new => '951', Object.new => '952', Object.new => '953', Object.new => '954', Object.new => '955', Object.new => '956', Object.new => '957', Object.new => '958', Object.new => '959', Object.new => '960', Object.new => '961', Object.new => '962', Object.new => '963', Object.new => '964', Object.new => '965', Object.new => '966', Object.new => '967', Object.new => '968', Object.new => '969', Object.new => '970', Object.new => '971', Object.new => '972', Object.new => '973', Object.new => '974', Object.new => '975', Object.new => '976', Object.new => '977', Object.new => '978', Object.new => '979', Object.new => '980', Object.new => '981', Object.new => '982', Object.new => '983', Object.new => '984', Object.new => '985', Object.new => '986', Object.new => '987', Object.new => '988', Object.new => '989', Object.new => '990', Object.new => '991', Object.new => '992', Object.new => '993', Object.new => '994', Object.new => '995', Object.new => '996', Object.new => '997', Object.new => '998', Object.new => '999'} +end + diff --git a/benchmark/bm_hash_literal_object_small.rb b/benchmark/bm_hash_literal_object_small.rb new file mode 100644 index 00000000..1a50ebbd --- /dev/null +++ b/benchmark/bm_hash_literal_object_small.rb @@ -0,0 +1,3 @@ +10_000.times do + h = {Object.new => 'b', Object.new => 'd', Object.new => 'f', Object.new => 'h', Object.new => 'j', Object.new => 'l', Object.new => 'n', Object.new => 'p'} +end diff --git a/benchmark/bm_hash_literal_string_large.rb b/benchmark/bm_hash_literal_string_large.rb new file mode 100644 index 00000000..fdf4f4dd --- /dev/null +++ b/benchmark/bm_hash_literal_string_large.rb @@ -0,0 +1,4 @@ +10_000.times do + h = {"0"=>"0", "1"=>"1", "2"=>"2", "3"=>"3", "4"=>"4", "5"=>"5", "6"=>"6", "7"=>"7", "8"=>"8", "9"=>"9", "10"=>"10", "11"=>"11", "12"=>"12", "13"=>"13", "14"=>"14", "15"=>"15", "16"=>"16", "17"=>"17", "18"=>"18", "19"=>"19", "20"=>"20", "21"=>"21", "22"=>"22", "23"=>"23", "24"=>"24", "25"=>"25", "26"=>"26", "27"=>"27", "28"=>"28", "29"=>"29", "30"=>"30", "31"=>"31", "32"=>"32", "33"=>"33", "34"=>"34", "35"=>"35", "36"=>"36", "37"=>"37", "38"=>"38", "39"=>"39", "40"=>"40", "41"=>"41", "42"=>"42", "43"=>"43", "44"=>"44", "45"=>"45", "46"=>"46", "47"=>"47", "48"=>"48", "49"=>"49", "50"=>"50", "51"=>"51", "52"=>"52", "53"=>"53", "54"=>"54", "55"=>"55", "56"=>"56", "57"=>"57", "58"=>"58", "59"=>"59", "60"=>"60", "61"=>"61", "62"=>"62", "63"=>"63", "64"=>"64", "65"=>"65", "66"=>"66", "67"=>"67", "68"=>"68", "69"=>"69", "70"=>"70", "71"=>"71", "72"=>"72", "73"=>"73", "74"=>"74", "75"=>"75", "76"=>"76", "77"=>"77", "78"=>"78", "79"=>"79", "80"=>"80", "81"=>"81", "82"=>"82", "83"=>"83", "84"=>"84", "85"=>"85", "86"=>"86", "87"=>"87", "88"=>"88", "89"=>"89", "90"=>"90", "91"=>"91", "92"=>"92", "93"=>"93", "94"=>"94", "95"=>"95", "96"=>"96", "97"=>"97", "98"=>"98", "99"=>"99", "100"=>"100", "101"=>"101", "102"=>"102", "103"=>"103", "104"=>"104", "105"=>"105", "106"=>"106", "107"=>"107", "108"=>"108", "109"=>"109", "110"=>"110", "111"=>"111", "112"=>"112", "113"=>"113", "114"=>"114", "115"=>"115", "116"=>"116", "117"=>"117", "118"=>"118", "119"=>"119", "120"=>"120", "121"=>"121", "122"=>"122", "123"=>"123", "124"=>"124", "125"=>"125", "126"=>"126", "127"=>"127", "128"=>"128", "129"=>"129", "130"=>"130", "131"=>"131", "132"=>"132", "133"=>"133", "134"=>"134", "135"=>"135", "136"=>"136", "137"=>"137", "138"=>"138", "139"=>"139", "140"=>"140", "141"=>"141", "142"=>"142", "143"=>"143", "144"=>"144", "145"=>"145", "146"=>"146", "147"=>"147", "148"=>"148", "149"=>"149", "150"=>"150", "151"=>"151", "152"=>"152", "153"=>"153", "154"=>"154", "155"=>"155", "156"=>"156", "157"=>"157", "158"=>"158", "159"=>"159", "160"=>"160", "161"=>"161", "162"=>"162", "163"=>"163", "164"=>"164", "165"=>"165", "166"=>"166", "167"=>"167", "168"=>"168", "169"=>"169", "170"=>"170", "171"=>"171", "172"=>"172", "173"=>"173", "174"=>"174", "175"=>"175", "176"=>"176", "177"=>"177", "178"=>"178", "179"=>"179", "180"=>"180", "181"=>"181", "182"=>"182", "183"=>"183", "184"=>"184", "185"=>"185", "186"=>"186", "187"=>"187", "188"=>"188", "189"=>"189", "190"=>"190", "191"=>"191", "192"=>"192", "193"=>"193", "194"=>"194", "195"=>"195", "196"=>"196", "197"=>"197", "198"=>"198", "199"=>"199", "200"=>"200", "201"=>"201", "202"=>"202", "203"=>"203", "204"=>"204", "205"=>"205", "206"=>"206", "207"=>"207", "208"=>"208", "209"=>"209", "210"=>"210", "211"=>"211", "212"=>"212", "213"=>"213", "214"=>"214", "215"=>"215", "216"=>"216", "217"=>"217", "218"=>"218", "219"=>"219", "220"=>"220", "221"=>"221", "222"=>"222", "223"=>"223", "224"=>"224", "225"=>"225", "226"=>"226", "227"=>"227", "228"=>"228", "229"=>"229", "230"=>"230", "231"=>"231", "232"=>"232", "233"=>"233", "234"=>"234", "235"=>"235", "236"=>"236", "237"=>"237", "238"=>"238", "239"=>"239", "240"=>"240", "241"=>"241", "242"=>"242", "243"=>"243", "244"=>"244", "245"=>"245", "246"=>"246", "247"=>"247", "248"=>"248", "249"=>"249", "250"=>"250", "251"=>"251", "252"=>"252", "253"=>"253", "254"=>"254", "255"=>"255", "256"=>"256", "257"=>"257", "258"=>"258", "259"=>"259", "260"=>"260", "261"=>"261", "262"=>"262", "263"=>"263", "264"=>"264", "265"=>"265", "266"=>"266", "267"=>"267", "268"=>"268", "269"=>"269", "270"=>"270", "271"=>"271", "272"=>"272", "273"=>"273", "274"=>"274", "275"=>"275", "276"=>"276", "277"=>"277", "278"=>"278", "279"=>"279", "280"=>"280", "281"=>"281", "282"=>"282", "283"=>"283", "284"=>"284", "285"=>"285", "286"=>"286", "287"=>"287", "288"=>"288", "289"=>"289", "290"=>"290", "291"=>"291", "292"=>"292", "293"=>"293", "294"=>"294", "295"=>"295", "296"=>"296", "297"=>"297", "298"=>"298", "299"=>"299", "300"=>"300", "301"=>"301", "302"=>"302", "303"=>"303", "304"=>"304", "305"=>"305", "306"=>"306", "307"=>"307", "308"=>"308", "309"=>"309", "310"=>"310", "311"=>"311", "312"=>"312", "313"=>"313", "314"=>"314", "315"=>"315", "316"=>"316", "317"=>"317", "318"=>"318", "319"=>"319", "320"=>"320", "321"=>"321", "322"=>"322", "323"=>"323", "324"=>"324", "325"=>"325", "326"=>"326", "327"=>"327", "328"=>"328", "329"=>"329", "330"=>"330", "331"=>"331", "332"=>"332", "333"=>"333", "334"=>"334", "335"=>"335", "336"=>"336", "337"=>"337", "338"=>"338", "339"=>"339", "340"=>"340", "341"=>"341", "342"=>"342", "343"=>"343", "344"=>"344", "345"=>"345", "346"=>"346", "347"=>"347", "348"=>"348", "349"=>"349", "350"=>"350", "351"=>"351", "352"=>"352", "353"=>"353", "354"=>"354", "355"=>"355", "356"=>"356", "357"=>"357", "358"=>"358", "359"=>"359", "360"=>"360", "361"=>"361", "362"=>"362", "363"=>"363", "364"=>"364", "365"=>"365", "366"=>"366", "367"=>"367", "368"=>"368", "369"=>"369", "370"=>"370", "371"=>"371", "372"=>"372", "373"=>"373", "374"=>"374", "375"=>"375", "376"=>"376", "377"=>"377", "378"=>"378", "379"=>"379", "380"=>"380", "381"=>"381", "382"=>"382", "383"=>"383", "384"=>"384", "385"=>"385", "386"=>"386", "387"=>"387", "388"=>"388", "389"=>"389", "390"=>"390", "391"=>"391", "392"=>"392", "393"=>"393", "394"=>"394", "395"=>"395", "396"=>"396", "397"=>"397", "398"=>"398", "399"=>"399", "400"=>"400", "401"=>"401", "402"=>"402", "403"=>"403", "404"=>"404", "405"=>"405", "406"=>"406", "407"=>"407", "408"=>"408", "409"=>"409", "410"=>"410", "411"=>"411", "412"=>"412", "413"=>"413", "414"=>"414", "415"=>"415", "416"=>"416", "417"=>"417", "418"=>"418", "419"=>"419", "420"=>"420", "421"=>"421", "422"=>"422", "423"=>"423", "424"=>"424", "425"=>"425", "426"=>"426", "427"=>"427", "428"=>"428", "429"=>"429", "430"=>"430", "431"=>"431", "432"=>"432", "433"=>"433", "434"=>"434", "435"=>"435", "436"=>"436", "437"=>"437", "438"=>"438", "439"=>"439", "440"=>"440", "441"=>"441", "442"=>"442", "443"=>"443", "444"=>"444", "445"=>"445", "446"=>"446", "447"=>"447", "448"=>"448", "449"=>"449", "450"=>"450", "451"=>"451", "452"=>"452", "453"=>"453", "454"=>"454", "455"=>"455", "456"=>"456", "457"=>"457", "458"=>"458", "459"=>"459", "460"=>"460", "461"=>"461", "462"=>"462", "463"=>"463", "464"=>"464", "465"=>"465", "466"=>"466", "467"=>"467", "468"=>"468", "469"=>"469", "470"=>"470", "471"=>"471", "472"=>"472", "473"=>"473", "474"=>"474", "475"=>"475", "476"=>"476", "477"=>"477", "478"=>"478", "479"=>"479", "480"=>"480", "481"=>"481", "482"=>"482", "483"=>"483", "484"=>"484", "485"=>"485", "486"=>"486", "487"=>"487", "488"=>"488", "489"=>"489", "490"=>"490", "491"=>"491", "492"=>"492", "493"=>"493", "494"=>"494", "495"=>"495", "496"=>"496", "497"=>"497", "498"=>"498", "499"=>"499", "500"=>"500", "501"=>"501", "502"=>"502", "503"=>"503", "504"=>"504", "505"=>"505", "506"=>"506", "507"=>"507", "508"=>"508", "509"=>"509", "510"=>"510", "511"=>"511", "512"=>"512", "513"=>"513", "514"=>"514", "515"=>"515", "516"=>"516", "517"=>"517", "518"=>"518", "519"=>"519", "520"=>"520", "521"=>"521", "522"=>"522", "523"=>"523", "524"=>"524", "525"=>"525", "526"=>"526", "527"=>"527", "528"=>"528", "529"=>"529", "530"=>"530", "531"=>"531", "532"=>"532", "533"=>"533", "534"=>"534", "535"=>"535", "536"=>"536", "537"=>"537", "538"=>"538", "539"=>"539", "540"=>"540", "541"=>"541", "542"=>"542", "543"=>"543", "544"=>"544", "545"=>"545", "546"=>"546", "547"=>"547", "548"=>"548", "549"=>"549", "550"=>"550", "551"=>"551", "552"=>"552", "553"=>"553", "554"=>"554", "555"=>"555", "556"=>"556", "557"=>"557", "558"=>"558", "559"=>"559", "560"=>"560", "561"=>"561", "562"=>"562", "563"=>"563", "564"=>"564", "565"=>"565", "566"=>"566", "567"=>"567", "568"=>"568", "569"=>"569", "570"=>"570", "571"=>"571", "572"=>"572", "573"=>"573", "574"=>"574", "575"=>"575", "576"=>"576", "577"=>"577", "578"=>"578", "579"=>"579", "580"=>"580", "581"=>"581", "582"=>"582", "583"=>"583", "584"=>"584", "585"=>"585", "586"=>"586", "587"=>"587", "588"=>"588", "589"=>"589", "590"=>"590", "591"=>"591", "592"=>"592", "593"=>"593", "594"=>"594", "595"=>"595", "596"=>"596", "597"=>"597", "598"=>"598", "599"=>"599", "600"=>"600", "601"=>"601", "602"=>"602", "603"=>"603", "604"=>"604", "605"=>"605", "606"=>"606", "607"=>"607", "608"=>"608", "609"=>"609", "610"=>"610", "611"=>"611", "612"=>"612", "613"=>"613", "614"=>"614", "615"=>"615", "616"=>"616", "617"=>"617", "618"=>"618", "619"=>"619", "620"=>"620", "621"=>"621", "622"=>"622", "623"=>"623", "624"=>"624", "625"=>"625", "626"=>"626", "627"=>"627", "628"=>"628", "629"=>"629", "630"=>"630", "631"=>"631", "632"=>"632", "633"=>"633", "634"=>"634", "635"=>"635", "636"=>"636", "637"=>"637", "638"=>"638", "639"=>"639", "640"=>"640", "641"=>"641", "642"=>"642", "643"=>"643", "644"=>"644", "645"=>"645", "646"=>"646", "647"=>"647", "648"=>"648", "649"=>"649", "650"=>"650", "651"=>"651", "652"=>"652", "653"=>"653", "654"=>"654", "655"=>"655", "656"=>"656", "657"=>"657", "658"=>"658", "659"=>"659", "660"=>"660", "661"=>"661", "662"=>"662", "663"=>"663", "664"=>"664", "665"=>"665", "666"=>"666", "667"=>"667", "668"=>"668", "669"=>"669", "670"=>"670", "671"=>"671", "672"=>"672", "673"=>"673", "674"=>"674", "675"=>"675", "676"=>"676", "677"=>"677", "678"=>"678", "679"=>"679", "680"=>"680", "681"=>"681", "682"=>"682", "683"=>"683", "684"=>"684", "685"=>"685", "686"=>"686", "687"=>"687", "688"=>"688", "689"=>"689", "690"=>"690", "691"=>"691", "692"=>"692", "693"=>"693", "694"=>"694", "695"=>"695", "696"=>"696", "697"=>"697", "698"=>"698", "699"=>"699", "700"=>"700", "701"=>"701", "702"=>"702", "703"=>"703", "704"=>"704", "705"=>"705", "706"=>"706", "707"=>"707", "708"=>"708", "709"=>"709", "710"=>"710", "711"=>"711", "712"=>"712", "713"=>"713", "714"=>"714", "715"=>"715", "716"=>"716", "717"=>"717", "718"=>"718", "719"=>"719", "720"=>"720", "721"=>"721", "722"=>"722", "723"=>"723", "724"=>"724", "725"=>"725", "726"=>"726", "727"=>"727", "728"=>"728", "729"=>"729", "730"=>"730", "731"=>"731", "732"=>"732", "733"=>"733", "734"=>"734", "735"=>"735", "736"=>"736", "737"=>"737", "738"=>"738", "739"=>"739", "740"=>"740", "741"=>"741", "742"=>"742", "743"=>"743", "744"=>"744", "745"=>"745", "746"=>"746", "747"=>"747", "748"=>"748", "749"=>"749", "750"=>"750", "751"=>"751", "752"=>"752", "753"=>"753", "754"=>"754", "755"=>"755", "756"=>"756", "757"=>"757", "758"=>"758", "759"=>"759", "760"=>"760", "761"=>"761", "762"=>"762", "763"=>"763", "764"=>"764", "765"=>"765", "766"=>"766", "767"=>"767", "768"=>"768", "769"=>"769", "770"=>"770", "771"=>"771", "772"=>"772", "773"=>"773", "774"=>"774", "775"=>"775", "776"=>"776", "777"=>"777", "778"=>"778", "779"=>"779", "780"=>"780", "781"=>"781", "782"=>"782", "783"=>"783", "784"=>"784", "785"=>"785", "786"=>"786", "787"=>"787", "788"=>"788", "789"=>"789", "790"=>"790", "791"=>"791", "792"=>"792", "793"=>"793", "794"=>"794", "795"=>"795", "796"=>"796", "797"=>"797", "798"=>"798", "799"=>"799", "800"=>"800", "801"=>"801", "802"=>"802", "803"=>"803", "804"=>"804", "805"=>"805", "806"=>"806", "807"=>"807", "808"=>"808", "809"=>"809", "810"=>"810", "811"=>"811", "812"=>"812", "813"=>"813", "814"=>"814", "815"=>"815", "816"=>"816", "817"=>"817", "818"=>"818", "819"=>"819", "820"=>"820", "821"=>"821", "822"=>"822", "823"=>"823", "824"=>"824", "825"=>"825", "826"=>"826", "827"=>"827", "828"=>"828", "829"=>"829", "830"=>"830", "831"=>"831", "832"=>"832", "833"=>"833", "834"=>"834", "835"=>"835", "836"=>"836", "837"=>"837", "838"=>"838", "839"=>"839", "840"=>"840", "841"=>"841", "842"=>"842", "843"=>"843", "844"=>"844", "845"=>"845", "846"=>"846", "847"=>"847", "848"=>"848", "849"=>"849", "850"=>"850", "851"=>"851", "852"=>"852", "853"=>"853", "854"=>"854", "855"=>"855", "856"=>"856", "857"=>"857", "858"=>"858", "859"=>"859", "860"=>"860", "861"=>"861", "862"=>"862", "863"=>"863", "864"=>"864", "865"=>"865", "866"=>"866", "867"=>"867", "868"=>"868", "869"=>"869", "870"=>"870", "871"=>"871", "872"=>"872", "873"=>"873", "874"=>"874", "875"=>"875", "876"=>"876", "877"=>"877", "878"=>"878", "879"=>"879", "880"=>"880", "881"=>"881", "882"=>"882", "883"=>"883", "884"=>"884", "885"=>"885", "886"=>"886", "887"=>"887", "888"=>"888", "889"=>"889", "890"=>"890", "891"=>"891", "892"=>"892", "893"=>"893", "894"=>"894", "895"=>"895", "896"=>"896", "897"=>"897", "898"=>"898", "899"=>"899", "900"=>"900", "901"=>"901", "902"=>"902", "903"=>"903", "904"=>"904", "905"=>"905", "906"=>"906", "907"=>"907", "908"=>"908", "909"=>"909", "910"=>"910", "911"=>"911", "912"=>"912", "913"=>"913", "914"=>"914", "915"=>"915", "916"=>"916", "917"=>"917", "918"=>"918", "919"=>"919", "920"=>"920", "921"=>"921", "922"=>"922", "923"=>"923", "924"=>"924", "925"=>"925", "926"=>"926", "927"=>"927", "928"=>"928", "929"=>"929", "930"=>"930", "931"=>"931", "932"=>"932", "933"=>"933", "934"=>"934", "935"=>"935", "936"=>"936", "937"=>"937", "938"=>"938", "939"=>"939", "940"=>"940", "941"=>"941", "942"=>"942", "943"=>"943", "944"=>"944", "945"=>"945", "946"=>"946", "947"=>"947", "948"=>"948", "949"=>"949", "950"=>"950", "951"=>"951", "952"=>"952", "953"=>"953", "954"=>"954", "955"=>"955", "956"=>"956", "957"=>"957", "958"=>"958", "959"=>"959", "960"=>"960", "961"=>"961", "962"=>"962", "963"=>"963", "964"=>"964", "965"=>"965", "966"=>"966", "967"=>"967", "968"=>"968", "969"=>"969", "970"=>"970", "971"=>"971", "972"=>"972", "973"=>"973", "974"=>"974", "975"=>"975", "976"=>"976", "977"=>"977", "978"=>"978", "979"=>"979", "980"=>"980", "981"=>"981", "982"=>"982", "983"=>"983", "984"=>"984", "985"=>"985", "986"=>"986", "987"=>"987", "988"=>"988", "989"=>"989", "990"=>"990", "991"=>"991", "992"=>"992", "993"=>"993", "994"=>"994", "995"=>"995", "996"=>"996", "997"=>"997", "998"=>"998", "999"=>"999"} +end + diff --git a/benchmark/bm_hash_literal_string_small.rb b/benchmark/bm_hash_literal_string_small.rb new file mode 100644 index 00000000..4d0d0f9a --- /dev/null +++ b/benchmark/bm_hash_literal_string_small.rb @@ -0,0 +1,3 @@ +100_000.times do + h = {'a' => 'b', 'c' => 'd', 'e' => 'f', 'g' => 'h', 'i' => 'j', 'k' => 'l', 'm' => 'n', 'o' => 'p'} +end diff --git a/benchmark/bm_hash_merge_object.rb b/benchmark/bm_hash_merge_object.rb new file mode 100644 index 00000000..6b00b15a --- /dev/null +++ b/benchmark/bm_hash_merge_object.rb @@ -0,0 +1,22 @@ +h1 = {} +h2 = {} + +a = [] + +1.upto(5_000) do |i| + a[i] = Object.new + h1[a[i]] = nil +end + +2_501.upto(7_500) do |i| + a[i] = Object.new + h2[a[i]] = nil +end + +500.times do + h1.merge!(h2) +end + +500.times do + h2.merge!(h1){|k, v, v2| 42} +end diff --git a/benchmark/bm_hash_merge_string.rb b/benchmark/bm_hash_merge_string.rb new file mode 100644 index 00000000..1d133f39 --- /dev/null +++ b/benchmark/bm_hash_merge_string.rb @@ -0,0 +1,18 @@ +h1 = {} +h2 = {} + +1.upto(5_000) do |i| + h1[i.to_s] = nil +end + +2_501.upto(7_500) do |i| + h2[i.to_s] = nil +end + +500.times do + h1.merge!(h2) +end + +500.times do + h2.merge!(h1){|k, v, v2| 42} +end diff --git a/benchmark/bm_hash_rassoc_object.rb b/benchmark/bm_hash_rassoc_object.rb new file mode 100644 index 00000000..cbc92dd4 --- /dev/null +++ b/benchmark/bm_hash_rassoc_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +1_000.times do |i| + k, v = h.rassoc(i) +end diff --git a/benchmark/bm_hash_rassoc_string.rb b/benchmark/bm_hash_rassoc_string.rb new file mode 100644 index 00000000..12e854f0 --- /dev/null +++ b/benchmark/bm_hash_rassoc_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +1_000.times do |i| + k, v = h.rassoc(i) +end diff --git a/benchmark/bm_hash_rehash_object.rb b/benchmark/bm_hash_rehash_object.rb new file mode 100644 index 00000000..dab1d1b5 --- /dev/null +++ b/benchmark/bm_hash_rehash_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do + h.rehash +end diff --git a/benchmark/bm_hash_rehash_string.rb b/benchmark/bm_hash_rehash_string.rb new file mode 100644 index 00000000..acb386b6 --- /dev/null +++ b/benchmark/bm_hash_rehash_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do + h.rehash +end diff --git a/benchmark/bm_hash_reject_bang_object.rb b/benchmark/bm_hash_reject_bang_object.rb new file mode 100644 index 00000000..af9bab76 --- /dev/null +++ b/benchmark/bm_hash_reject_bang_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +10_000.times do |i| + h.reject!{|k, v| v <= i} +end diff --git a/benchmark/bm_hash_reject_bang_string.rb b/benchmark/bm_hash_reject_bang_string.rb new file mode 100644 index 00000000..e02920cd --- /dev/null +++ b/benchmark/bm_hash_reject_bang_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +10_000.times do |i| + h.reject!{|k, v| v <= i} +end diff --git a/benchmark/bm_hash_reject_object.rb b/benchmark/bm_hash_reject_object.rb new file mode 100644 index 00000000..cbccec52 --- /dev/null +++ b/benchmark/bm_hash_reject_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +100.times do |i| + h.reject{|k, v| v % 2 == 0} +end diff --git a/benchmark/bm_hash_reject_string.rb b/benchmark/bm_hash_reject_string.rb new file mode 100644 index 00000000..102590ef --- /dev/null +++ b/benchmark/bm_hash_reject_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +100.times do |i| + h.reject{|k, v| v % 2 == 0} +end diff --git a/benchmark/bm_hash_replace_object.rb b/benchmark/bm_hash_replace_object.rb new file mode 100644 index 00000000..45351f73 --- /dev/null +++ b/benchmark/bm_hash_replace_object.rb @@ -0,0 +1,18 @@ +h1 = {} +h2 = {} + +a = [] + +1.upto(5_000) do |i| + a[i] = Object.new + h1[a[i]] = nil +end + +2_501.upto(7_500) do |i| + a[i] = Object.new + h2[a[i]] = nil +end + +1_000.times do + h1.replace(h2) +end diff --git a/benchmark/bm_hash_replace_string.rb b/benchmark/bm_hash_replace_string.rb new file mode 100644 index 00000000..2a8e6e13 --- /dev/null +++ b/benchmark/bm_hash_replace_string.rb @@ -0,0 +1,14 @@ +h1 = {} +h2 = {} + +1.upto(5_000) do |i| + h1[i.to_s] = nil +end + +2_501.upto(7_500) do |i| + h2[i.to_s] = nil +end + +1_000.times do + h1.replace(h2) +end diff --git a/benchmark/bm_hash_select_bang_object.rb b/benchmark/bm_hash_select_bang_object.rb new file mode 100644 index 00000000..45c50711 --- /dev/null +++ b/benchmark/bm_hash_select_bang_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +10_000.times do |i| + h.select!{|k, v| v > i} +end diff --git a/benchmark/bm_hash_select_bang_string.rb b/benchmark/bm_hash_select_bang_string.rb new file mode 100644 index 00000000..2092b8ba --- /dev/null +++ b/benchmark/bm_hash_select_bang_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +10_000.times do |i| + h.select!{|k, v| v > i} +end diff --git a/benchmark/bm_hash_select_object.rb b/benchmark/bm_hash_select_object.rb new file mode 100644 index 00000000..122aee14 --- /dev/null +++ b/benchmark/bm_hash_select_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = i +end + +100.times do |i| + h.select{|k, v| v % 2 == 0} +end diff --git a/benchmark/bm_hash_select_string.rb b/benchmark/bm_hash_select_string.rb new file mode 100644 index 00000000..964ebb5c --- /dev/null +++ b/benchmark/bm_hash_select_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = i +end + +100.times do |i| + h.select{|k, v| v % 2 == 0} +end diff --git a/benchmark/bm_hash_shift_object.rb b/benchmark/bm_hash_shift_object.rb new file mode 100644 index 00000000..cb5e3aff --- /dev/null +++ b/benchmark/bm_hash_shift_object.rb @@ -0,0 +1,10 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000_000.times do + k, v = h.shift + h[k] = v +end diff --git a/benchmark/bm_hash_shift_string.rb b/benchmark/bm_hash_shift_string.rb new file mode 100644 index 00000000..7ee5754e --- /dev/null +++ b/benchmark/bm_hash_shift_string.rb @@ -0,0 +1,10 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000_000.times do + k, v = h.shift + h[k] = v +end diff --git a/benchmark/bm_hash_to_a_object.rb b/benchmark/bm_hash_to_a_object.rb new file mode 100644 index 00000000..5d607596 --- /dev/null +++ b/benchmark/bm_hash_to_a_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +5_000.times do + h.to_a +end diff --git a/benchmark/bm_hash_to_a_string.rb b/benchmark/bm_hash_to_a_string.rb new file mode 100644 index 00000000..aba71311 --- /dev/null +++ b/benchmark/bm_hash_to_a_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +5_000.times do + h.to_a +end diff --git a/benchmark/bm_hash_to_h_object.rb b/benchmark/bm_hash_to_h_object.rb new file mode 100644 index 00000000..839a6b9e --- /dev/null +++ b/benchmark/bm_hash_to_h_object.rb @@ -0,0 +1,10 @@ +class MyHash < Hash; end +h = MyHash.new + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do + h.to_h +end diff --git a/benchmark/bm_hash_to_h_string.rb b/benchmark/bm_hash_to_h_string.rb new file mode 100644 index 00000000..74df8d4f --- /dev/null +++ b/benchmark/bm_hash_to_h_string.rb @@ -0,0 +1,10 @@ +class MyHash < Hash; end +h = MyHash.new + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do + h.to_h +end diff --git a/benchmark/bm_hash_values_object.rb b/benchmark/bm_hash_values_object.rb new file mode 100644 index 00000000..47d16a87 --- /dev/null +++ b/benchmark/bm_hash_values_object.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[Object.new] = nil +end + +1_000.times do + h.values +end diff --git a/benchmark/bm_hash_values_string.rb b/benchmark/bm_hash_values_string.rb new file mode 100644 index 00000000..507874c5 --- /dev/null +++ b/benchmark/bm_hash_values_string.rb @@ -0,0 +1,9 @@ +h = {} + +10_000.times do |i| + h[i.to_s] = nil +end + +1_000.times do + h.values +end diff --git a/benchmark/bm_module_definition_big.rb b/benchmark/bm_module_definition_big.rb new file mode 100644 index 00000000..6480cd22 --- /dev/null +++ b/benchmark/bm_module_definition_big.rb @@ -0,0 +1,400 @@ +module Scope0 + module Scope1 + module Scope2 + module Scope3 + module Scope4 + module Scope5 + module Scope6 + module Scope7 + module Scope8 + module Scope9 + module Scope10 + module Scope11 + module Scope12 + module Scope13 + module Scope14 + module Scope15 + module Scope16 + module Scope17 + module Scope18 + module Scope19 + module Scope20 + module Scope21 + module Scope22 + module Scope23 + module Scope24 + module Scope25 + module Scope26 + module Scope27 + module Scope28 + module Scope29 + module Scope30 + module Scope31 + module Scope32 + module Scope33 + module Scope34 + module Scope35 + module Scope36 + module Scope37 + module Scope38 + module Scope39 + module Scope40 + module Scope41 + module Scope42 + module Scope43 + module Scope44 + module Scope45 + module Scope46 + module Scope47 + module Scope48 + module Scope49 + module Scope50 + module Scope51 + module Scope52 + module Scope53 + module Scope54 + module Scope55 + module Scope56 + module Scope57 + module Scope58 + module Scope59 + module Scope60 + module Scope61 + module Scope62 + module Scope63 + module Scope64 + module Scope65 + module Scope66 + module Scope67 + module Scope68 + module Scope69 + module Scope70 + module Scope71 + module Scope72 + module Scope73 + module Scope74 + module Scope75 + module Scope76 + module Scope77 + module Scope78 + module Scope79 + module Scope80 + module Scope81 + module Scope82 + module Scope83 + module Scope84 + module Scope85 + module Scope86 + module Scope87 + module Scope88 + module Scope89 + module Scope90 + module Scope91 + module Scope92 + module Scope93 + module Scope94 + module Scope95 + module Scope96 + module Scope97 + module Scope98 + module Scope99 + module Scope100 + module Scope101 + module Scope102 + module Scope103 + module Scope104 + module Scope105 + module Scope106 + module Scope107 + module Scope108 + module Scope109 + module Scope110 + module Scope111 + module Scope112 + module Scope113 + module Scope114 + module Scope115 + module Scope116 + module Scope117 + module Scope118 + module Scope119 + module Scope120 + module Scope121 + module Scope122 + module Scope123 + module Scope124 + module Scope125 + module Scope126 + module Scope127 + module Scope128 + module Scope129 + module Scope130 + module Scope131 + module Scope132 + module Scope133 + module Scope134 + module Scope135 + module Scope136 + module Scope137 + module Scope138 + module Scope139 + module Scope140 + module Scope141 + module Scope142 + module Scope143 + module Scope144 + module Scope145 + module Scope146 + module Scope147 + module Scope148 + module Scope149 + module Scope150 + module Scope151 + module Scope152 + module Scope153 + module Scope154 + module Scope155 + module Scope156 + module Scope157 + module Scope158 + module Scope159 + module Scope160 + module Scope161 + module Scope162 + module Scope163 + module Scope164 + module Scope165 + module Scope166 + module Scope167 + module Scope168 + module Scope169 + module Scope170 + module Scope171 + module Scope172 + module Scope173 + module Scope174 + module Scope175 + module Scope176 + module Scope177 + module Scope178 + module Scope179 + module Scope180 + module Scope181 + module Scope182 + module Scope183 + module Scope184 + module Scope185 + module Scope186 + module Scope187 + module Scope188 + module Scope189 + module Scope190 + module Scope191 + module Scope192 + module Scope193 + module Scope194 + module Scope195 + module Scope196 + module Scope197 + module Scope198 + module Scope199 + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end +end diff --git a/benchmark/bm_module_definition_small.rb b/benchmark/bm_module_definition_small.rb new file mode 100644 index 00000000..c6b0b61c --- /dev/null +++ b/benchmark/bm_module_definition_small.rb @@ -0,0 +1,30 @@ +module Scope0 + module Scope1 + module Scope2 + module Scope3 + module Scope4 + module Scope5 + module Scope6 + module Scope7 + module Scope8 + module Scope9 + module Scope10 + module Scope11 + module Scope12 + module Scope13 + module Scope14 + end + end + end + end + end + end + end + end + end + end + end + end + end + end +end diff --git a/benchmark/run.rb b/benchmark/run.rb new file mode 100644 index 00000000..b5b07edd --- /dev/null +++ b/benchmark/run.rb @@ -0,0 +1,55 @@ +if RUBY_ENGINE == 'opal' + require 'opal/compiler' + require 'nodejs' +end + +BEST_OF_N = Integer(ENV['BEST_OF_N']) rescue 1 + +require 'benchmark' + +files = ARGV + +if files.empty? + files = File.read('benchmark/benchmarks').lines.map(&:strip).reject do |line| + line.empty? || line.start_with?('#') + end +end + +files = files.shuffle + +maxlen = files.max_by{|file| file.length}.length + 1 + +total_time = 0 + +files.each do |file| + print file, " " * (maxlen - file.length) + + times = [] + + if RUBY_ENGINE == 'opal' + code = File.read(file) + code = "Benchmark.measure { #{code} }" + code = Opal.compile(code, file: file) + + BEST_OF_N.times do + times << `eval(code)` + end + else + code = File.read(file) + code = "Benchmark.measure { #{code} }" + + BEST_OF_N.times do + times << eval(code) + end + end + + time = times.min_by{|t| t.real} + + total_time += time.real + + print time.real, "\n" +end + +bottom_line = "Executed #{ files.length } benchmark#{ 's' if files.length != 1} in #{ total_time } sec" +$stderr.print "=" * bottom_line.length, "\n" +$stderr.print bottom_line, "\n" diff --git a/bin/build b/bin/build index b31df2db..b31bae95 100755 --- a/bin/build +++ b/bin/build @@ -25,6 +25,8 @@ end ENV['GIT_DIR'] = opal.join('.git').to_s git :fetch, '--all', '--prune' +git :checkout, 'master' +git :reset, '--hard', 'origin/master' ENV['GIT_DIR'] = nil opal_version = root.join("tmp/#{version}") @@ -64,5 +66,7 @@ system "#{__dir__}/set-current", current git 'add', '.' git 'commit', '-a', '-m', version git 'push' -git 'tag', version -git 'push', '--tags' +unless version == 'master' + git 'tag', version + git 'push', '--tags' +end diff --git a/bin/build-browser-source-map-support b/bin/build-browser-source-map-support new file mode 100755 index 00000000..f0e6674a --- /dev/null +++ b/bin/build-browser-source-map-support @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +yarn -s browserify -r ./lib/opal/cli_runners/source-map-support.js -o ./lib/opal/cli_runners/source-map-support-browser.js -s sourceMapSupport +yarn -s browserify -r ./lib/opal/cli_runners/source-map-support.js -o ./lib/opal/cli_runners/source-map-support-node.js --bare -s sourceMapSupport diff --git a/bin/console b/bin/console new file mode 100755 index 00000000..ed1a3db3 --- /dev/null +++ b/bin/console @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "opal" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/bin/format-filters b/bin/format-filters new file mode 100755 index 00000000..46ffc92b --- /dev/null +++ b/bin/format-filters @@ -0,0 +1,54 @@ +#!/usr/bin/env ruby + +sort_lines = -> lines { + lines.sort.uniq { |l| l.split('" # ', 2).first } +} + +write_group = ->(title:, lines:, type:) { + %{#{type} "#{title}" do\n}+ + sort_lines[lines].join+ + %{end\n} +} + +write_groups = -> groups { + %{# NOTE: run bin/format-filters after changing this file\n}+ + groups.map.with_index do |group, index| + puts "- #{group[:type]} #{group[:title].inspect}..." + ("\n" if index > 0).to_s + write_group.call(**group) + end.join +} + +group_lines = -> lines { + groups = [] + group = nil + lines.each do |line| + case line + when /^(opal_(?:unsupported_)?filter) *"([^"]+)" *do *\n/ + raise "bad group for #{line.inspect}!" if group + + group = { + type: $1, + title: $2, + lines: [] + } + + when /^ fails/ + group[:lines] << line + + when /^end/ + groups << group + group = nil + end + end + groups +} + +format_filter = -> path { + File.write path, write_groups[group_lines[File.read(path).lines]] +} + +Dir['spec/filters/**/*.rb'].each do |path| + puts + puts "Formatting #{path} ..." + format_filter[path] +end diff --git a/bin/git-submodule-fast-install b/bin/git-submodule-fast-install new file mode 100755 index 00000000..24660cb5 --- /dev/null +++ b/bin/git-submodule-fast-install @@ -0,0 +1,49 @@ +#!/usr/bin/env ruby + +def system(*args) + puts "== command: #{args.inspect}" + super +end + +def system!(*args) + system(*args) or raise "== command failed: #{args.inspect}" +end + + +Dir.chdir "#{__dir__}/.." +Dir.mkdir 'tmp' unless File.directory? 'tmp' + +system 'git submodule --quiet deinit --all -f 2> /dev/null' + +modules = {} +`git config -f #{__dir__}/../.gitmodules --list`.lines.each do |line| + fullkey, value = line.split('=', 2) + _, name, key = fullkey.split('.', 3) + modules[name] ||= {} + modules[name][key.to_sym] = value.strip +end + +`git submodule`.lines.each do |line| + sha1, name = line[1..-1].scan(/^(?\w+) (?\S+)/).first + modules[name][:sha1] = sha1 +end + +modules.map do |name, config| + puts "== installing #{name}..." + url, sha1, path = config.values_at(:url, :sha1, :path) + dir = File.dirname(path) + url.sub!(/\.git$/, '') + + Thread.new do + system! "curl -L #{url}/archive/#{sha1}.zip -o #{sha1}.zip" + + system! "unzip -q #{sha1}.zip -d #{dir}" + system! "rm #{sha1}.zip" + + system! "rm -rf #{path}" if File.directory? path + system! "mv #{dir}/*-#{sha1} #{path}" + print "== completed installing #{name}.\n" + end +end.each(&:join) + +system! 'git submodule init' diff --git a/bin/opal b/bin/opal new file mode 100755 index 00000000..ce754abf --- /dev/null +++ b/bin/opal @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require 'bundler/setup' +load "#{__dir__}/../exe/opal" diff --git a/bin/opal-benchmark-ips b/bin/opal-benchmark-ips new file mode 100755 index 00000000..339ba6b7 --- /dev/null +++ b/bin/opal-benchmark-ips @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby + +file = ARGV.shift +if ARGV.any? + warn "usage example:\n\n #{$0} benchmark-ips/bm_case.rb\n" + exit 1 +end +exec 'bundle', 'exec', 'rake', 'bench:ips', "FILE=#{file}" diff --git a/bin/opal-mspec b/bin/opal-mspec new file mode 100755 index 00000000..fc2c271c --- /dev/null +++ b/bin/opal-mspec @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require 'bundler/setup' + +specs = ARGV.map do |s| + s.end_with?('.rb') ? s : "#{s}/**/*_spec.rb" +end + +env = {} +env['PATTERN'] = "{#{specs.join(',')}}" if specs.any? +exec env, 'rake', 'mspec' diff --git a/bin/opal-repl b/bin/opal-repl new file mode 100755 index 00000000..d6724ad3 --- /dev/null +++ b/bin/opal-repl @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +exec "#{__dir__}/opal", '--repl', *ARGV diff --git a/bin/rake b/bin/rake new file mode 100755 index 00000000..1e6eacd3 --- /dev/null +++ b/bin/rake @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rake", "rake") diff --git a/bin/remove-filters b/bin/remove-filters new file mode 100755 index 00000000..647c9688 --- /dev/null +++ b/bin/remove-filters @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +# This is an utility to automatically remove a group of filters provided +# to its standard input. +# +# This utility is to assist with removing a large group of filters spread +# around multiple files that is being output by a command: +# +# rake mspec_ruby_nodejs RUBYSPECS=true INVERT_RUNNING_MODE=true +# +# It expects an input of format: +# 1) "Set#filter! returns an Enumerator when passed no block" +# 2) "Set#filter! yields every element of self" +# 3) "Set#filter! keeps every element from self for which the passed block returns true" +# 4) "Set#filter! returns self when self was modified" +# 5) "Set#filter! returns nil when self was not modified" + +filters = $stdin.read.split("\n").map do |i| + i.scan(/(?:\d+\)|fails) (".*")/).first.first +end.compact +filters = Regexp.union(*filters) + +remove_filters = -> path { + file = File.read(path).split("\n") + + remove, good = file.partition { |i| i =~ filters } + + if remove.length > 0 + puts "Removing #{remove.length} filters from #{path}" + + File.write(path, good.join("\n")+"\n") + end +} + +Dir['spec/filters/**/*.rb'].each do |path| + remove_filters[path] +end diff --git a/bin/setup b/bin/setup new file mode 100755 index 00000000..e8276910 --- /dev/null +++ b/bin/setup @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +gem install bundler --conservative + +bundle update + +git submodule update --init + +bin/yarn install diff --git a/bin/yarn b/bin/yarn new file mode 100755 index 00000000..460dd565 --- /dev/null +++ b/bin/yarn @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + begin + exec "yarnpkg", *ARGV + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/config.ru b/config.ru new file mode 100644 index 00000000..c12407b4 --- /dev/null +++ b/config.ru @@ -0,0 +1,14 @@ +require 'bundler' +Bundler.require + +require 'mspec/opal/rake_task' + +::Opal::Config.arity_check_enabled = true +::Opal::Config.dynamic_require_severity = :error + +use Rack::ShowExceptions +use Rack::ShowStatus +use MSpec::Opal::Index +run MSpec::Opal::Environment.new + + diff --git a/docs/async.md b/docs/async.md new file mode 100644 index 00000000..8425a485 --- /dev/null +++ b/docs/async.md @@ -0,0 +1,109 @@ +# Asynchronous code (PromiseV2 / async / await) + +Please be aware that this functionality is marked as experimental and may change +in the future. + +In order to disable the warnings that will be shown if you use those experimental +features, add the following line before requiring `promise/v2` or `await` and after +requiring `opal`. + +```ruby +`Opal.config.experimental_features_severity = 'ignore'` +``` + +## PromiseV2 + +In Opal 1.2 we introduced PromiseV2 which is to replace the default Promise in Opal 2.0 +(which will become PromiseV1). Right now it's experimental, but the interface of PromiseV1 +stay unchanged and will continue to be supported. + +It is imperative that during the transition period you either `require 'promise/v1'` or +`require 'promise/v2'` and then use either `PromiseV1` or `PromiseV2`. + +If you write library code it's imperative that you don't require the promise itself, but +detect if `PromiseV2` is defined and use the newer implementation, for instance using the +following code: + +```ruby +module MyLibrary + Promise = defined?(PromiseV2) ? PromiseV2 : ::Promise +end +``` + +The difference between `PromiseV1` and `PromiseV2` is that `PromiseV1` is a pure-Ruby +implementation of a Promise, while `PromiseV2` is reusing the JavaScript `Promise`. Both are +incompatible with each other, but `PromiseV2` can be awaited (see below) and they translate +1 to 1 to the JavaScript native `Promise` (they are bridged; you can directly return a +`Promise` from JavaScript API without a need to translate it). The other difference is that +`PromiseV2` always runs a `#then` block a tick later, while `PromiseV1` would could run it +instantaneously. + +## Async/await + +In Opal 1.3 we implemented the CoffeeScript pattern of async/await. As of now, it's hidden +behind a magic comment, but this behavior may change in the future. + +Example: + +```ruby +# await: true + +require "await" + +def wait_5_seconds + puts "Let's wait 5 seconds..." + sleep(5).await + puts "Done!" +end + +wait_5_seconds.__await__ +``` + +It's important to understand what happens under the hood: every scope in which `#__await__` is +encountered will become async, which means that it will return a Promise that will resolve +to a value. This includes methods, blocks and the top scope. This means, that `#__await__` is +infectious and you need to remember to `#__await__` everything along the way, otherwise +a program will finish too early and the values may be incorrect. + +[You can take a look at how we ported Minitest to support asynchronous tests.](https://github.com/opal/opal/pull/2221/commits/8383c7b45a94fe4628778f429508b9c08c8948b0) Take note, that +it was ported to use `#await` while the finally accepted version uses `#__await__`. + +It is certainly correct to `#__await__` any value, including non-Promises, for instance +`5.__await__` will correctly resolve to `5` (except that it will make the scope an async +function, with all the limitations described above). + +The `await` stdlib module includes a few useful functions, like async-aware `each_await` +function and `sleep` that doesn't block the thread. It also includes a method `#await` +which is an alias of `#itself` - it makes sense to auto-await that method. + +This approach is certainly incompatible with what Ruby does, but due to a dynamic nature +of Ruby and a different model of JavaScript this was the least invasive way to catch up +with the latest JavaScript trends and support `Promise` heavy APIs and asynchronous code. + +## Auto-await + +The magic comment also accepts a comma-separated list of methods to be automatically +awaited. An individual value can contain a wildcard character `*`. For instance, +those two blocks of code are equivalent: + +```ruby +# await: true + +require "await" + +[1,2,3].each_await do |i| + p i + sleep(i).__await__ +end.__await__ +``` + +```ruby +# await: sleep, *await* + +require "await" + +[1,2,3].each_await do |i| + p i + sleep i +end +``` \ No newline at end of file diff --git a/docs/compiled_ruby.md b/docs/compiled_ruby.md new file mode 100644 index 00000000..4ba8d5c7 --- /dev/null +++ b/docs/compiled_ruby.md @@ -0,0 +1,681 @@ +# Compiled Ruby Code + +## Generated JavaScript + +Opal is a source-to-source compiler, so there is no VM as such and the +compiled code aims to be as fast and efficient as possible, mapping +directly to underlying javascript features and objects where possible. + +### Literals + +```ruby +nil # => nil +true # => true +false # => false +self # => self +``` + +**self** is mostly compiled to `this`. Methods and blocks are implemented +as javascript functions, so their `this` value will be the right +`self` value. Class bodies and the top level scope use a `self` variable +to improve readability. + +**nil** is compiled to a `nil` javascript variable. `nil` is a real object +which allows methods to be called on it. Opal cannot send methods to `null` +or `undefined`, and they are considered bad values to be inside ruby code. + +**true** and **false** are compiled directly into their native boolean +equivalents. This makes interaction a lot easier as there is no need +to convert values to opal specific values. + +NOTE: Because `true` and `false` compile to their native +javascript equivalents, they must share the same class: `Boolean`. +Thru some level of hackery, we make them pseudo-members of the appropriate +`TrueClass` and `FalseClass`. + +#### Strings & Symbols + +```ruby +"hello world!" # => "hello world!" +:foo # => "foo" +<<-EOS # => "Hello there.\n" +Hello there. +EOS +``` + +Ruby strings are compiled directly into JavaScript strings for +performance as well as readability. This has the side effect that Opal +does not support mutable strings - i.e. all strings are immutable. + +NOTE: Strings in Opal are immutable because they are compiled into regular JavaScript strings. This is done for performance reasons. + +For performance reasons, symbols are also compiled directly into strings. +Opal supports all the symbol syntaxes, but does not have a real `Symbol` +class. Symbols and Strings can therefore be used interchangeably. + +#### Numbers + +In Opal there is a single class for numbers; `Number`. To keep Opal +as performant as possible, Ruby numbers are mapped to native numbers. +This has the side effect that all numbers must be of the same class. +Most relevant methods from `Integer` and `Float` are implemented on +this class. + +```ruby +42 # => 42 +3.142 # => 3.142 +``` + +#### Arrays + +Ruby arrays are compiled directly into JavaScript arrays. Special +Ruby syntaxes for word arrays etc are also supported. + +```ruby +[1, 2, 3, 4] # => [1, 2, 3, 4] +%w[foo bar baz] # => ["foo", "bar", "baz"] +``` + +#### Hash + +Inside a generated Ruby script, a function `Opal.hash` is available which +creates a new hash. This is also available in JavaScript as `Opal.hash` +and simply returns a new instance of the `Hash` class. + +```ruby +{ :foo => 100, :baz => 700 } # => Opal.hash("foo", 100, "baz", 700) +{ foo: 42, bar: [1, 2, 3] } # => Opal.hash("foo", 42, "bar", [1, 2, 3]) +``` + +#### Range + +Similar to hash, there is a function `Opal.range` available to create +range instances. + +```ruby +1..4 # => Opal.range(1, 4, true) +3...7 # => Opal.range(3, 7, false) +``` + +### Logic and conditionals + +As per Ruby, Opal treats only `false` and `nil` as falsy, everything +else is a truthy value including `""`, `0` and `[]`. This differs from +JavaScript as these values are also treated as false. + +For this reason, most truthy tests must check if values are `false` or +`nil` (we also check for `null` and `undefined`). + +Taking the following test: + +```ruby +val = 42 + +if val + return 3.142; +end +``` + +This would be compiled into: + +```javascript +val = 42; +if (val !== false && val !== nil && val != null) { + return 3.142 +} else { + return nil +}; +``` + +This makes the generated truthy tests (`if` statements, `and` checks and +`or` statements) a little more verbose in the generated code. + +### Instance variables + +Instance variables in Opal work just as expected. When ivars are set or +retrieved on an object, they are set natively without the `@` prefix. +This allows real JavaScript identifiers to be used which is more +efficient then accessing variables by string name. + +```ruby +@foo = 200 +@foo # => 200 + +@bar # => nil +``` + +This gets compiled into: + +```javascript +this.foo = 200; +this.foo; // => 200 + +this.bar; // => nil +``` + +NOTE: If an instance variable uses the same name as a reserved JavaScript keyword, +then the instance variable is wrapped using the object-key notation: `this['class']`. + +## Compiled Files + +As described above, a compiled Ruby source gets generated into a string +of JavaScript code that is wrapped inside an anonymous function. This +looks similar to the following: + +```javascript +(function(Opal) { + // some setup code code + return self.$puts("foo") +})(Opal); +``` + +As a complete example, assuming the following code: + +```ruby +puts "foo" +``` + +This would compile directly into: + +```javascript +Opal.queue(function(Opal) { + var self = Opal.top, nil = Opal.nil; + + Opal.add_stubs('puts'); + return self.$puts("foo") +}); +``` + +**TIP:** + +you can see the compiled code with this command: `opal --compile --no-exit --no-opal --eval 'puts "foo"'` +or, more briefly: `opal -cEO -e 'puts "foo"'` + + +### Using compiled sources + +If you write the generated code as above into a file `app.js` and add +that to your HTML page, then it is obvious that `"foo"` would be +written to the browser's console. + +### Debugging and finding errors + +Because Opal does not aim to be fully compatible with Ruby, there are +some instances where things can break and it may not be entirely +obvious what went wrong. + +### Using JavaScript debuggers + +As Opal just generates JavaScript, it is useful to use a native +debugger to work through JavaScript code. To use a debugger, simply +add a `debugger` statement: + +```ruby +# .. code +debugger +# .. more code +``` + +The `debugger` statement is compiled to become a JavaScript `debugger` +statement. This statement breaks the code if you have your Inspector open. + +NOTE: All local variables and method/block arguments also keep their Ruby +names except in the rare cases when the name is reserved in JavaScript. +In these cases, a `$` suffix is added to the name +(e.g. `try` → `try$`). + + +## JavaScript from Ruby + +Opal tries to interact as cleanly with JavaScript and its api as much +as possible. Ruby arrays, strings, numbers, regexps, blocks and booleans +are just JavaScript native equivalents. The only boxed core features are +hashes. + + +### Inline JavaScript + +As most of the corelib deals with these low level details, Opal provides +a special syntax for inlining JavaScript code. This is done with +x-strings or "backticks", as their Ruby use has no useful translation +in the browser. + +```ruby +`window.title` +# => "Opal: Ruby to JavaScript compiler" + +%x{ + console.log("opal version is:"); + console.log(#{ RUBY_ENGINE_VERSION }); +} + +# => opal version is: +# => 1.3.1 +``` + +Even interpolations are supported, as seen here. + +This feature of inlining code is used extensively, for example in +Array#length: + +```ruby +class Array + def length + `this.length` + end +end +``` + +X-Strings also have the ability to automatically return their value, +as used by this example. + + +### Native Module + +_Reposted from: [Mikamayhem](http://dev.mikamai.com/post/79398725537/using-native-javascript-objects-from-opal)_ + +Opal standard lib (stdlib) includes a `Native` module. To use it, you need to download and reference `native.js`. You can find the latest minified one from the CDN [here](http://cdn.opalrb.com/opal/current/native.min.js). + +Let's see how it works and wrap `window`: + +```ruby +require 'native' + +win = Native(`window`) # equivalent to Native::Object.new(`window`) +``` + +To access a Native-wrapped global JavaScript object, we can also use `$$`, after +we have the `native` module required. + +Now what if we want to access one of its properties? + +```ruby +win[:location][:href] # => "http://dev.mikamai.com/" +win[:location][:href] = "http://mikamai.com/" # will bring you to mikamai.com +``` + +And what about methods? + +```ruby +win.alert('hey there!') +``` + +So let’s do something more interesting: + +```ruby +class << win + # A cross-browser window close method (works in IE!) + def close! + %x{ + return (#@native.open('', '_self', '') && #@native.close()) || + (#@native.opener = null && #@native.close()) || + (#@native.opener = '' && #@native.close()); + } + end + + # let's assign href directly + def href= url + self[:location][:href] = url + end +end +``` + +That’s all for now, bye! + +```ruby +win.close! +``` + +### Calling JavaScript Methods + +You can make direct JavaScript method calls on using the `recv.JS.method` +syntax. For example, if you have a JavaScript object named `foo` and want to call the +`bar` method on it with no arguments, with or without parentheses: + +```ruby +# javascript: foo.bar() +foo.JS.bar +foo.JS.bar() +``` + +You can call the JavaScript methods with arguments, with or without parentheses, just +like Ruby methods: + +```ruby +# JavaScript: foo.bar(1, "a") +foo.JS.bar(1, :a) +foo.JS.bar 1, :a +``` + +You can call the JavaScript methods with argument splats: + +```ruby +# JavaScript: ($a = foo).bar.apply($a, [1].concat([2, 3])) +foo.JS.bar(1, *[2, 3]) +foo.JS.bar 1, *[2, 3] +``` + +You can provide a block when making a JavaScript method call, and it will be +converted to a JavaScript function added as the last argument to the method: + +```ruby +# JavaScript: +# ($a = (TMP_1 = function(arg){ +# var self = TMP_1.$$s || this; +# if (arg == null) arg = nil; +# return "" + (arg.method()) + " " + (self.$baz(3)) +# }, +# TMP_1.$$s = self, TMP_1), +# foo.bar)(1, 2, $a); +foo.JS.bar(1, 2){|arg| arg.JS.method + baz(3)} +``` + +Note how `self` is set for the JavaScript function passed as an argument. This +allows normal Ruby block behavior to work when passing blocks to JavaScript +methods. + +The `.JS.` syntax is recognized as a special token by the lexer, so if you have +a Ruby method named `JS` that you want to call, you can add a space to call it: + +```ruby +# call Ruby JS method on foo, call Ruby bar method on result +foo. JS.bar +``` + +### Getting/Setting JavaScript Properties + +You can get JavaScript properties using the `recv.JS[:property]` syntax: + +```ruby +# JavaScript: foo["bar"] +foo.JS[:bar] +``` + +This also works for JavaScript array access: + +```ruby +# JavaScript: foo[2] +foo.JS[2] +``` + +You can set JavaScript properties using this as the left hand side in an +assignment: + +```ruby +# JavaScript: foo["bar"] = 1 +foo.JS[:bar] = 1 +``` + +This also works for setting values in a JavaScript array: + +```ruby +# JavaScript: foo[2] = "a" +foo.JS[2] = :a +``` + +Like the `recv.JS.method` syntax, `.JS[` is recognized as a special token by +the lexer, so if you want to call the Ruby `JS` method on a object and then +call the Ruby `[]` method on the result, you can add a space: + +```ruby +# call Ruby JS method on foo, call Ruby [] method on result with :a argument +foo. JS[:a] +``` + +### Calling JavaScript Operators + +Opal has a `js` library in the stdlib that provides a `JS` module which can +be used to call JavaScript operators such as `new`. Example: + +```ruby +require 'js' + +# new foo(bar) +JS.new(foo, bar) + +# delete foo["bar"] +JS.delete(foo, :bar) + +# "bar" in foo +JS.in(:bar, foo) + +# foo instanceof bar +JS.instanceof(foo, bar) + +# typeof foo +JS.typeof(foo) +``` + +### Calling JavaScript Global Functions + +You can also use the `js` library to call JavaScript global functions via +`JS.call`: + +```ruby +require 'js' + +# parseFloat("1.1") +JS.call(:parseFloat, "1.1") +``` + +For convenience, `method_missing` is aliased to call, allowing you to call +global JavaScript methods directly on the `JS` module: + +```ruby +require 'js' + +# parseFloat("1.1") +JS.parseFloat("1.1") +``` + + +### Wrapping JavaScript Libraries + +If you want to integrate a JavaScript library with Opal, so that you can make Ruby calls, you can choose one of the following options: + +- **Use backticks:** This is the quickest, simplest approach to integrating: call the native JavaScript code directly; it may provide a slight performance benefit, but also produces "ugly" Ruby code riddled with JavaScript. It's ideal for occasional calls to a JavaScript library. + +- **Use `.JS`:** You can make direct JavaScript method calls on using the `recv.JS.method` syntax. It is very similar to using backticks but looks more like ruby. + +- **Use `Native`:** `Native` provides a reasonable Ruby-like wrapper around JavaScript objects. This provides a quick in-term solution if no dedicated Ruby wrapper library exists. + +- **Create your own Wrapper Library:** If you use the library a lot, you can create your own Ruby library that wraps the JavaScript calls (which call `Native` or use backticks under the hood). This provides the best abstraction (eg. you can provide high-level calls that provide functionality, regardless of if the underlying JavaScript call flows change). + + +## Ruby from JavaScript + +Accessing classes and methods defined in Opal from the JavaScript runtime is +possible via the `Opal` JS object. Consider following code: + +```ruby +module Bar + BAR = 123 +end + +class Foo + include Bar + FOO = 456 + + def foo + puts "called #foo on class ::Foo defined in Ruby code" + end +end + +BAZ = 789 +``` + +### Navigating constants + +Top level constants can be accessed as properties of `Opal`: + + +```javascript +Opal.Object; // => Object +Opal.Kernel; // => Kernel +Opal.Array; // => Array +Opal.RUBY_VERSION; // => "2.3" +Opal.Foo; // => Foo +Opal.BAZ; // => 789 +``` + +To reach nested constants the safest way is to call `#const_get` on `Object`: + +```javascript +Opal.Object.$const_get('Bar::BAR'); // => 123 +Opal.Object.$const_get('Foo::BAR'); // => 123 +Opal.Object.$const_get('Foo::FOO'); // => 456 +Opal.Object.$const_get('BAZ'); // => 789 +``` + +Constants can also be navigated using the `$$` property, although this is limited to constants defined directly under the current object: + +```javascript +Opal.Bar.$$.BAR // => 123 +Opal.Foo.$$.FOO // => 456 +Opal.Foo.$$.BAR // => undefined +``` + +A later feature also allows you to skip the `$$` property: + +```javascript +Opal.Bar.BAR // => 123 +Opal.Foo.FOO // => 456 +Opal.Foo.BAR // => undefined +``` + + +### Calling methods + +**Methods** are always prefixed by a single `$`: + +```javascript +// Equivalent to: +// Foo.new.foo +Opal.Foo.$new().$foo(); // => "called #foo on class ::Foo defined in Ruby code" + +// Equivalent to: +// "hello there".sub('there', 'world') +("hello there").$sub('there', 'world'); // => "hello world" +``` + +**Methods names unsupported in JS** should be called using the JS bracket notation: + +```javascript +// Equivalent to: +// hash = Hash.new["key"] = "value" +// hash["key"] = "value" +var hash = Opal.Hash.$new(); // => {} +hash["$[]="]("key", "value"); // => "value" + +// Equivalent to: +// [1,2,3].reverse! +[1,2,3]['$reverse!'](); // => [3,2,1] + +// Equivalent to: +// 1 == 2 +(1)['$=='](2); // => false +``` + +**Passing blocks** from JS is a bit more tricky, so the suggested solution is to use `Opal.send(…)`: + +```javascript +// Equivalent to: +// [1,2,3].map {|n| n * 2} +Opal.send([1,2,3], 'map', [], function(n) {return n * 2}); // => [2,4,6] +``` + +Alternatively blocks can also be called *the hard way* by assigning the block-function to the property `$$p` of the method: + +```javascript +// Equivalent to: +// [1,2,3].map {|n| n * 2} +array = [1,2,3] +array.$map.$$p = function(n) {return n * 2}; // "$$p" stands for "proc" +array.$map(); // => [2,4,6] +``` + + + +### Hash + +Since Ruby hashes are implemented directly with an Opal class, there's no "toll-free" bridging available (unlike with strings and arrays, for example). However, it's quite possible to interact with hashes from JavaScript: + +```javascript +var myHash = Opal.hash({a: 1, b: 2}); +// output of $inspect: {"a"=>1, "b"=>2} +myHash.$store('a', 10); +// output of $inspect: {"a"=>10, "b"=>2} +myHash.$fetch('b',''); +// 2 +myHash.$fetch('z',''); +// "" +myHash.$update(Opal.hash({b: 20, c: 30})); +// output of $inspect: {"a"=>10, "b"=>20, "c"=>30} +myHash.$to_n(); // provided by the Native module +// output: {"a": 10, "b": 20, "c": 30} aka a standard JavaScript object +``` + +NOTE: Be aware `Hash#to_n` produces a duplicate copy of the hash. + +## Advanced Compilation + +### Method Missing + +Opal supports `method_missing`. This is a key feature of Ruby, and Opal wouldn't be much use without it! This page details the implementation of `method_missing` for Opal. + +#### Method dispatches + +Firstly, a Ruby call `foo.bar 1, 2, 3` is compiled into the following JavaScript: + +```javascript +foo.$bar(1, 2, 3) +``` + +This should be pretty easy to read. The `bar` method has a `$` prefix just to distinguish it from underlying JavaScript properties, as well as Ruby ivars. Methods are compiled like this to make the generated code really readable. + +#### Handling `method_missing` + +JavaScript does not have an equivalent of `method_missing`, so how do we handle it? If a function is missing in JavaScript, then a language level exception will be raised. + +To get around this, we make use of our compiler. During parsing, we collect a list of all method calls made inside a Ruby file, and this gives us a list of all possible method calls. We then add stub methods to the root object prototype (an Opal object, not the global JavaScript Object) which will proxy our method missing calls for us. + +For example, assume the following Ruby script: + +```ruby +first 1, 2, 3 +second "wow".to_sym +``` + +After parsing, we know we only ever call 3 methods: `[:first, :second, :to_sym]`. So, imagine we could just add these 3 methods to `BasicObject` in Ruby, we would get something like this: + +```ruby +class BasicObject + def first(*args, &block) + method_missing(:first, *args, &block) + end + + def second(*args, &block) + method_missing(:second, *args, &block) + end + + def to_sym(*args, &block) + method_missing(:to_sym, *args, &block) + end +end +``` + +It is obvious from here, that unless an object defines any given method, it will always resort in a dispatch to `method_missing` from one of our defined stub methods. This is how we get `method_missing` in Opal. + +#### Optimising generated code + +To optimise the generated code slightly, we reduce the code output from the compiler into the following JavaScript: + +```javascript +Opal.add_stubs("first,second,to_sym"]); +``` + +You will see this at the top of all your generated JavaScript files. This will add a stub method for all methods used in your file. + +#### Alternative approaches + +The old approach was to inline `method_missing` calls by checking for a method on **every method dispatch**. This is still supported via a parser option, but not recommended. diff --git a/docs/compiler.md b/docs/compiler.md new file mode 100644 index 00000000..7ec0543b --- /dev/null +++ b/docs/compiler.md @@ -0,0 +1,33 @@ +# Opal Compiler + +Opal is a source to source compiler. It accepts ruby code as a string and +generates javascript code which can be run in any environment. Generated +code relies on the opal runtime which provides the class system and some +other runtime helpers. + +## Compiler stages + +The compiler can be broken down into 3 separate stages: + +* lexing/parsing +* code generation + +### Lexer/Parser + +The [opal parser][parser] relies on the `parser` gem, see debug/development documentation there to know more about its internals: https://whitequark.github.io/parser/. + +### Code generation + +The [opal compiler][compiler] takes these sexps from the parser +and generates ruby code from them. Each type of sexp has [its own node type][base-node] +used to generate javascript. Each node creates an array of one or more +[fragments][fragments] which are the concatenated together to +form the final javascript. Fragments are used as they contain the generated +code as well as a reference back to the original sexp which is useful for +generating source maps afterwards. + + +[sexps]: https://github.com/opal/opal/tree/master/lib/opal/parser/sexp.rb +[compiler]: https://github.com/opal/opal/tree/master/lib/opal/compiler.rb +[fragments]: https://github.com/opal/opal/tree/master/lib/opal/fragment.rb +[base-node]: https://github.com/opal/opal/tree/master/lib/opal/nodes/base.rb diff --git a/docs/compiler_directives.md b/docs/compiler_directives.md new file mode 100644 index 00000000..ef54dcbc --- /dev/null +++ b/docs/compiler_directives.md @@ -0,0 +1,133 @@ +# Compiler Directives + +The Opal compiler supports some special directives that can optimize or +enhance the output of compiled Ruby code to suit the Ruby environment. + +## Require Directive + +All calls to `require` are captured so that the compiler and build tools +can determine which dependencies a file has. In the case of `Builder`, +these are collated and then added to a list of files to be processed. + +### `require` + +Assuming we have a file `foo.rb`: + + # foo.rb + require 'bar' + require 'baz' + +The compiler will collect these two dependencies, and then `Builder` +will attempt to discover them within the Opal load path to also compile +them into the target output. If these dependencies cannot be resolved, +then a compile time error will be thrown. + +#### Dynamic Requires + +Opal only supports hard-coded requires. This means that any dynamically +generated require statements cannot be discovered. Opal may raise an +error or just produce a warning if a dynamic require is used. A dynamic +require is any require that cannot be resolved using static analysis. A +common use case of dynamic requires is to include a directory of Ruby +files. In this case, see `require_tree` below. + +### `require_relative` + +`require_relative` is also supported by Opal's compiler for ahead-of-time +inclusion. + + # foo.rb + require_relative 'bar' + +This example will try to resolve `bar.rb` in the same directory. + +### `autoload` + +`autoload` is used to load a modules and classes within a modules +namespace. As long as the string argument given to `autoload` can be +resolved in Opal's load paths, in the same way as `require`, then these +referenced dependencies will also be compiled. + + # foo.rb + module Foo + autoload :Bar, 'bar' + end + +In this example, `bar.rb` will also be required. + +### `require_tree` + +`require_tree` can be used as an Opal-friendly alternative to globbing +over a directory to require a list of dependencies. + + # foo.rb + require_tree './models' + +This will, at compile time, resolve all files inside the `models/` +directory and also compile them to the output. At runtime this method +will then loop over all modules defined, and require them if they match +that given module path. + +Note: The given directory **must** be inside Opal's load path, otherwise +no files will be compiled. + +### Handling non-Ruby requirements + +Opal's `require` method is also special as it allows non-Ruby source +files to be required and generated in the output. The obvious example of +this is requiring JavaScript source files. JavaScript sources are +treated as first class citizens in Opal. The Opal gem also supports +compiling `.erb` files using the same process. + +## Opal Specific Code Compilation + +A special case `if` and `unless` statements can hide or show blocks of +code from the Opal compiler. These check against `RUBY_ENGINE` or +`RUBY_PLATFORM`. As these are valid Ruby statements against constants +that exist in all Ruby runtimes, they will not affect any running code: + +```ruby +if RUBY_ENGINE == 'opal' + # this code compiles +else + # this code never compiles +end +``` + +Unless statements are also supported: + +```ruby +unless RUBY_ENGINE == 'opal' + # this code will not run +end +``` + + +Also `!=` statements work: + +```ruby +if RUBY_ENGINE != 'opal' + puts 'do not run this code' +end +``` + + +These blocks of code don't run at all at runtime, but they also never +compile so will never be in the output JavaScript code. This is +particularly useful for using code in both MRI and Opal. + +Some uses are: + + * Avoid `require` statements being picked up by Opal compile time + require handling. + + * To stop certain requires taking place for Opal (and vice-versa for + shared libraries). + + * To wrap x-strings which might break in compiled JavaScript output. + + * To simply avoid compiling large blocks of code that are not needed + in the JavaScript/Opal version of an app. + +In all these examples `RUBY_PLATFORM` can be used instead of +`RUBY_ENGINE`. diff --git a/docs/configuring_gems.md b/docs/configuring_gems.md new file mode 100644 index 00000000..f27ef88b --- /dev/null +++ b/docs/configuring_gems.md @@ -0,0 +1,148 @@ +# Configuring Gems For Opal + +To configure a gem to run in Opal the gem will need a couple of things: + +1. The opal gem running on a server (so the ruby code can get compiled to JavaScript). +2. The Opal search path has to know to look for your gem when it is required. + +This is done by having the following 2 lines in your outermost .rb file: + +```ruby +require 'opal' +Opal.append_path File.expand_path('..', __FILE__).untaint +``` + +However it only makes sense to execute these lines outside of Opal, since what they do is set things up for Opal to find and compile the files to .js. So how these lines get added to your gem depends on whether the gem can usefully run in the normal server environment as well as in Opal, or just strictly in Opal. + +For example, you have a gem that parses, validates, and gives details on email addresses. This gem would be just as useful on the server, as running +in the browser. + +On the other hand you have a gem that does something with the DOM. There would be no point in making this gem available to the server. + +Each case is detailed below, assuming you have a Gem file structure like this: + + +``` +/lib + /your_gem_directory + /your_gem_file1.rb + /your_gem_file2.rb + /... + /version.rb + /your_gem.rb +``` + +## Configuring Gems To Run Everywhere + +If your gem will work both in Opal and in a classic ruby environment +your outer .rb file (`your_gem.rb`) needs to look like this + +```ruby +# require all the files, regardless of whether this code is running +# to run on the server, or inside of Opal. +require_relative 'your_gem_directory/your_gem_file1.rb' +require_relative 'your_gem_directory/your_gem_file2.rb' +# etc +require_relative 'your_gem_directory/version' +unless RUBY_ENGINE == 'opal' + # Now if we are NOT running inside of opal, set things up so opal can find + # the files. The whole thing is rescued in case the opal gem is not available. + # This would happen if the gem is being used server side ONLY. + begin + require 'opal' + Opal.append_path File.expand_path('..', __FILE__).untaint + rescue LoadError + end +end +``` + +So lets see what happens here. + +1. Somebody is going to require this file, perhaps implicitly (for example you are running in rails.) +2. Standard ruby is going to execute the `require`s, which will load your gem sources, then +3. because the `RUBY_ENGINE` is _not_ `opal`, Opal will be required, and your directory of sources added to Opal's search path. +4. Someplace else in some Opal code, the gem will _again_ be required, and so opal searches and finds the gem, +5. and runs this file again, _but now inside_ of the Opal environment. This time the `RUBY_ENGINE` _is_ Opal so the `require 'opal'` etc will not be executed. + +The result is that you have two versions of the code, one in standard ruby, and a second compiled to .js and ready to be served. + +## Configuring Gems To Run In Opal Only + +If it makes no sense to run the code in standard Ruby (i.e. on the server) then the above code can look like this: + +```ruby +# require all the files, only if Opal is executing +if RUBY_ENGINE == 'opal' + require_relative 'your_gem_directory/your_gem_file1.rb' + require_relative 'your_gem_directory/your_gem_file2.rb' + # etc + require_relative 'your_gem_directory/version' +else + # NOT running inside of opal, set things up + # so opal can find the files. + require 'opal' + Opal.append_path File.expand_path('..', __FILE__).untaint +end +``` + +## Testing + +Regardless of which case your gem is designed for, you will want to make sure you test inside the Opal environment. If nothing else you will want to make sure you have all the above configuration setup correctly. + +To do this add the following to your gemspec: + +```ruby +spec.add_development_dependency "opal-rspec" +spec.add_development_dependency "opal" +``` + +Then setup the following in config.ru (assuming your specs are in the /spec directory.) + +```ruby +require 'bundler' +Bundler.require + +require 'opal-rspec' +Opal.append_path File.expand_path('../spec', __FILE__) + +run Opal::Server.new { |s| + s.main = 'opal/rspec/sprockets_runner' + s.append_path 'spec' + s.debug = false + s.index_path = 'spec/index.html.erb' +} +``` + +Finally create a index.html.erb file in the spec directory with the following contents: + +```html + + + + + + <%= javascript_include_tag @server.main %> + + +``` + +With all this setup, you can run specs normally to test standard ruby execution, and then do + + bundle exec rackup + +and point your browser to localhost, and you will see your spec results running in the Opal environment. + +Don't forget to checkout the added features of the opal-rspec gem such as async specs. + +## Conditional Execution + +In some cases you might have to check whether you are in Opal or not, just wrap the code in: + +```ruby +if RUBY_ENGINE == 'opal' + # … +end +``` + +This might happen in your specs or in the actual gem code. + diff --git a/docs/encoding.md b/docs/encoding.md new file mode 100644 index 00000000..f9b38c76 --- /dev/null +++ b/docs/encoding.md @@ -0,0 +1,13 @@ +# Encoding + +Encoding support is partial and mostly given by the encoding set by the HTML page. +We suggest to always set encoding to UTF-8 explicitly: + +```html + + + + + +``` + diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000..d245745a --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,17 @@ +# FAQ + +### Why does Opal exist? + +To try and keep ruby relevant in a world where client-side applications are making javascript the primary development platform. + +### How compatible is Opal? + +We run opal against the [ruby spec](https://github.com/ruby/spec) as our primary testing setup. We try to make Opal as compatible as possible, whilst also taking into account restrictions of JavaScript when applicable. Opal supports the majority of ruby syntax features, as well as a very large part of the corelib implementation. We support method\_missing, modules, classes, instance\_exec, blocks, procs and lots lots more. Opal can compile and run RSpec unmodified, as well as self hosting the compiler at runtime. + +### What version of ruby does Opal target? + +We are running tests under ruby 3.0.0 conditions, but are mostly compatible with 2.6 level features. + +### Why doesn't Opal support mutable strings? + +All strings in Opal are immutable because ruby strings just get compiled directly into javascript strings, which are immutable. Wrapping ruby strings as a custom JavaScript object would add a lot of overhead as well as making interaction between ruby and javascript libraries more difficult. diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 00000000..0d46c588 --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,47 @@ +# Getting Started + +Opal is a ruby to javascript compiler, an implementation of the ruby corelib and stdlib, and associated gems for building fast client side web applications in ruby. + +## Installation + +Opal is available as a gem, and can be installed via: + +``` +$ gem install opal +``` + +Or added to your Gemfile as: + +```ruby +gem 'opal' +``` + +## Getting started with Opal + +At its very core, opal provides a simple method of compiling a string of ruby into javascript that can run on top of the opal runtime, provided by `opal.js`: + +```ruby +Opal.compile("[1, 2, 3].each { |a| puts a }") +# => "(function() { ... })()" +``` + +`opal` includes sprockets support for compiling Ruby (and ERB) assets, and treating them as first class JavaScript citizens. It works in a similar way to CoffeeScript, where JavaScript files can simply require Ruby sources, and Ruby sources can require JavaScript and other Ruby files. + +This relies on the Opal load path. Any gem containing opal code registers that directory to the Opal load path. Opal will then use all Opal load paths when running sprockets instances. For rails applications, `opal-rails` does this automatically. For building a simple application, we have to do this manually. + + +### Adding lookup paths + +Opal uses a load path which works with sprockets to create a set of locations which opal can require files +from. If you want to add a directory to this load path, you can add it to the global environment. + +In the `Opal` module, a property `paths` is used to hold the load paths which +`Opal` uses to require files from. You can add a directory to this: + +```ruby +Opal.append_path '../my_lib' +``` + +Now, any ruby files in this directory can be discovered. + + diff --git a/docs/headless_chrome.md b/docs/headless_chrome.md new file mode 100644 index 00000000..9a5e1120 --- /dev/null +++ b/docs/headless_chrome.md @@ -0,0 +1,95 @@ +# Headless Chrome + +## Requirements + +First of all, make sure that you have Chrome at least 59.0 installed. + +## Using the runner + +To run your code using headless chrome, use `-R chrome` (`--runner chrome`) option: + + $ opal -Rchrome -e "puts 'Hello, Opal'" + Hello, Opal + +The runner also listens for any exceptions and prints formatted stracktraces back to your console: + + $ opal -Rchrome -e " + def raising_method + raise 'test error' + end + + raising_method + " + + RuntimeError: test error + from :2693:7:in `
' + from -e:1:1:in `undefined' + +## Using exit codes + +By default headless chrome runner explicitly sets exit code to 1 when there was any error in the code. + + $ opal -Rchrome -e "42"; echo $? + 0 + + $ opal -Rchrome -e "raise 'error'"; echo $? + RuntimeError: error + from :2693:7:in `
' + from -e:1:1:in `undefined' + 1 + +You can change final exit code by using `Kernel#exit`, but make sure to require `opal/platform` in your code. + + $ opal -Rchrome -ropal/platform -e "exit(0)"; echo $? + 0 + + $ opal -Rchrome -ropal/platform -e "exit(1)"; echo $? + 1 + +Also `Kernel#exit` doesn't abort your script. It simply takes the value that was passed to the first +invocation and persists it in `window.OPAL_EXIT_CODE`. Later headless chrome runner extracts it from the chrome runtime. + +## Known limitations + +1. `exit` doesn't abort you script (but `raise/throw` does) +2. When you call `console.log(one, two, three)` from your code headless chrome prints only the first passed object. + The reason behind it is the format of the message that chrome sends to the runner. + Opal intentionally uses a simplified method from Chrome API (`Console.messageAdded`) to catch `console.log` invocations. + (Check `lib/opal/cli_runners/chrome.js` do get more information) + +## Internals + +Under the hood when you call `opal -Rchrome -e 'your code'` Opal uses chrome runner that is defined in +`lib/opal/cli_runners/chrome.rb`. This runner tries to connect to `localhost:9222` (9222 is a default port for a headless chrome server) +or runs the server on its own. It detects your platform and uses a default path to the chrome executable +(`Opal::CliRunners::Chrome#chrome_executable`) but you can override it by specifying `GOOGLE_CHROME_BINARY` environment +variable. + +When the server is up and running it passes compiled js code to `lib/opal/cli_runners/chrome_cdp_interface.rb` +as a plain input using stdin (basically, it's a second part of the runner). +`chrome_cdp_interface.rb` is a node js + Opal script that does the main job. It runs any provided code on the running chrome server, +catches errors and forwards console messages. + + +## Using a remote chrome server + +If you want to change a default chrome port or your chrome server is running on a different host:port +you can override default values by specifying `CHROME_HOST` and `CHROME_PORT` environment variables: + + $ CHROME_HOST=10.10.10.10 CHROME_PORT=8080 opal -Rchrome -e "puts 42" + Connecting to 10.10.10.10:8080... + 42 + +NOTE: `CHROME_HOST` requires a chrome server to be started. You can't start remotely a server on a different host. + + +## Additional options + +If you need to pass additional CLI options to the Chrome executable you can do so by setting the `CHROME_OPTS` environment variable: + + $ CHROME_OPTS="--window-size=412,732" opal -Rchrome -e "puts 42" + 42 + +Docker users may need `CHROME_OPTS="--no-sandbox"` due to the user namespaces limitations. + +_For a list of additional options see https://developers.google.com/web/updates/2017/04/headless-chrome_ diff --git a/docs/jquery.md b/docs/jquery.md new file mode 100644 index 00000000..92977854 --- /dev/null +++ b/docs/jquery.md @@ -0,0 +1,292 @@ +# JQuery + +`opal-jquery` offers a nicer ruby-like syntax for JQuery. It is useful for projects which cannot use `opal-browser` due to a reliance on jquery for plugins or other libraries. + +```ruby +foos = Element.find('.foo') +# => [
, ...] + +foos.class +# => JQuery + +foos.on(:click) do + alert "element was clicked" +end +``` + +### Getting Started + +#### Installation + +`opal-jquery` is distributed as a gem, and needs to be added to your `Gemfile`: + +```ruby +# Gemfile +gem 'opal' +gem 'opal-jquery' +``` + +#### Usage + +`opal-jquery` can now be easily added to your opal application sources: + +```ruby +# app/application.rb + +# Remember to compile opal-jquery with your javascript application. +# See "Compiling" below for an example on compiling dependencies. +require 'opal/jquery' + +alert "Hello from jquery + opal" +``` + +The `#alert` method is provided by `opal-jquery`. If the message displays, then +`jquery` support should be working. + + +#### Compiling + +When compiling your application to javascript, you must be sure to include both +Opal and Opal-JQuery so they'll be available to your application: + +```ruby +require 'opal' +require 'opal-jquery' + +builder = Opal::Builder.new +builder.build('opal') +builder.build('opal-jquery') +builder.build('./app/application.rb') + +File.write('application.js', builder.to_s) +``` + +then simply load the compiled file in your html: + +```html + + + + + + + + +``` + +NOTE: opal-jquery expects a jquery library to be loaded. This example loads it +remotely from jquery.com, but a locally downloaded copy works just as well, or- +if you're using rails- jquery may be included automatically. + +This example builds opal, opal-jquery and the application into a single `.js` file, +but you may build them separately, if you so choose. Just remember to include +each respective script in your html! + +### How does opal-jquery work + +`opal-jquery` provides an `Element` class, whose instances are toll-free +bridged instances of jquery objects. Just like ruby arrays are just javascript +arrays, `Element` instances are just jquery objects. This makes interaction +with jquery plugins much easier. + +### Interacting with the DOM + +#### Finding Elements + +opal-jquery provides the `Element` class, which can be used to find elements in +the current document: + +```ruby +Element.find('#header') +``` + +`Element.find` is aliased to `Element[]`: + +```ruby +Element['.my-class'] +``` + +These methods acts just like `$('selector')`, and can use any jQuery +compatible selector: + +```ruby +Element.find('#navigation li:last') +``` + +The result is just a jQuery instance, which is toll-free bridged to +instances of the `Element` class in ruby: + +```ruby +Element.find('.foo').class +# => Element +``` + +Instances of `Element` also have the `#find` method available for +finding elements within the scope of each DOM node represented by +the instance: + +```ruby +el = Element.find('#header') +el.find '.foo' +# => # +``` + +#### Running code on document ready + +Just like jQuery, opal-jquery requires the document to be ready to +be able to fully interact with the page. Any top level access should +use the `ready?` method: + +```ruby +Document.ready? do + alert "document is ready to go!" +end +``` + +The `Kernel#alert` method is shown above too. + +#### Event handling + +The `Element#on` method is used to attach event handlers to elements: + +```ruby +Element.find('#header').on :click do + puts "The header was clicked!" +end +``` + +Selectors can also be passed as a second argument to handle events +on certain children: + +```ruby +Element.find('#header').on(:click, '.foo') do + puts "An element with a 'foo' class was clicked" +end +``` + +An `Event` instance is optionally passed to block handlers as well, +which is toll-free bridged to jquery events: + +```ruby +Element.find('#my_link').on(:click) do |evt| + evt.stop_propagation + puts "stopped the event!" +end +``` + +You can access the element which triggered the event by `#current_target`. + +```ruby +Document.on :click do |evt| + puts "clicked on: #{evt.current_target}" +end +``` + +#### CSS styles and classnames + +The various jQuery methods are available on `Element` instances: + +```ruby +foo = Element.find('.foo') + +foo.add_class 'blue' +foo.remove_class 'foo' +foo.toggle_class 'selected' +``` + +There are also added convenience methods for opal-jquery: + +```ruby +foo = Element.find('#header') + +foo.class_name +# => 'red lorry' + +foo.class_name = 'yellow house' + +foo.class_name +# => 'yellow house' +``` + +`Element#css` also exists for getting/setting css styles: + +```ruby +el = Element.find('#container') +el.css 'color', 'blue' +el.css 'color' +# => 'blue' +``` + +### HTTP/AJAX requests + +jQuery's Ajax implementation is also wrapped in the top level HTTP +class. + +```ruby +HTTP.get("/users/1.json") do |response| + puts response.body + # => "{\"name\": \"Adam Beynon\"}" +end +``` + +The block passed to this method is used as the handler when the request +succeeds, as well as when it fails. To determine whether the request +was successful, use the `ok?` method: + +```ruby +HTTP.get("/users/2.json") do |response| + if response.ok? + alert "successful!" + else + alert "request failed :(" + end +end +``` + +It is also possible to use a different handler for each case: + +```ruby +request = HTTP.get("/users/3.json") + +request.callback { + puts "Request worked!" +} + +request.errback { + puts "Request didn't work :(" +} +``` + +The request is actually triggered inside the `HTTP.get` method, but due +to the async nature of the request, the callback and errback handlers can +be added anytime before the request returns. + +#### Handling responses + +Web apps deal with JSON responses quite frequently, so there is a useful +`#json` helper method to get the JSON content from a request: + +```ruby +HTTP.get("/users.json") do |response| + puts response.body + puts response.json +end + +# => "[{\"name\": \"Adam\"},{\"name\": \"Ben\"}]" +# => [{"name" => "Adam"}, {"name" => "Ben"}] +``` + +The `#body` method will always return the raw response string. + +If an error is encountered, then the `#status_code` method will hold the +specific error code from the underlying request: + +```ruby +request = HTTP.get("/users/3.json") + +request.callback { puts "it worked!" } + +request.errback { |response| + puts "failed with status #{response.status_code}" +} +``` diff --git a/docs/opal_parser.md b/docs/opal_parser.md new file mode 100644 index 00000000..eb1d0aaa --- /dev/null +++ b/docs/opal_parser.md @@ -0,0 +1,55 @@ +# Parsing Ruby from JavaScript with `opal-parser` + +Generally is best to precompile Ruby source files to JavaScript server-side but sometimes may become useful to be able to compile Ruby to JavaScript directly from JS. + +Opal is able to compile its – pure Ruby – compiler to JavaScript (how cool is that!). The whole compiler chain is available in the `stdlib` as `opal-parser`. + +```ruby +require 'opal-parser' +``` + +_Note: For the best performance and application load times, it is strongly recommended to design your application so that it won't need the parser. A lot of methods described in this document are more fun hacks than robust solutions. But if you really want or need to use them, for example so that you can implement a Ruby REPL or an interactive Ruby playground - we have you covered, but for all other cases, we strongly discourage you to take an advice from this guide._ + + +## Features + +### `Kernel#eval` + +`opal-parser` provides a partial implementation of `Kernel#eval`. + +Example: + +```ruby +require 'opal-parser' +eval "puts 'hello world!'" +``` + + +### `Kernel#require_remote` + +Will fetch a remote URL (by means of a sync `XMLHttpRequest`) and evaluate its contents as Ruby code. + +Example: + +```ruby +require 'opal-parser' +require_remote 'http://pastie.org/pastes/10444960/text' +HelloWorld.new.say_hello! +``` + + +### `Opal.compile()` and `Opal.eval()` (JavaScript) + +After requiring `opal-parser` both `Opal.compile()` and `Opal.eval()` functions are added to the JavaScript API. + +`Opal.compile(string, options)` (JavaScript) will forward the call to `Opal.compile` (Ruby) converting options from a plain JS object to a Ruby Hash. +`Opal.eval(string)` will compile the given code to JavaScript and then pass it to the [native `eval()` function][eval]. + + +### Support for ` + + + + +``` + +Now, open this html file and check the browsers console. You should see our +message printed in the console. diff --git a/docs/templates.md b/docs/templates.md new file mode 100644 index 00000000..5e5c89eb --- /dev/null +++ b/docs/templates.md @@ -0,0 +1,150 @@ +# Templates with Opal + +Opal includes support for running erb templates on the client. Haml templates +can also be used via the `opal-haml` gem. + +## Basic Templates + +If you require `template.rb` from the stdlib, then all compiled templates will +be available on the `Template` object. Each compiled template will be an +instance of `Template`, which provides a basic standard rendering api to make +rendering a uniform method on the client. + +For example, to access a template named `user`: + +```ruby +require 'template' + +template = Template['user'] +context = User.new('Ford Prefect') + +puts template.render(context) +# => "
...
" +``` + +`#render()` will run the template in the given context, and return the result +as a string. This is usually a html string, but it can be used for any dynamic +content. + +### Registered Templates + +You can get a quick list of all registered templates using `.paths`: + +```ruby +Template.paths +# => [#, #] +``` + +These names are the keys used to access a template: + +```ruby +Template['login'] +# => # +``` + +## Haml templates + +`opal-haml` allows `.haml` templates to be compiled, just like opal compiles +ruby code, ready to run on the client. + +To get started, add to your Gemfile: + +```ruby +# Gemfile +gem 'opal' +gem 'opal-haml' +``` + +`opal-haml` simply registers the `.haml` template to be handled under sprockets. +This means, that you can simply `require()` a haml template in your code. + +Lets say you have the following simple opal app: + +```ruby +# app/application.rb +require 'opal' + +class User < Struct.new(:name, :age) +end +``` + +We want to create an instance of the `User` class and render it using a haml +template. Lets first create that template as `app/views/user.haml`: + +```haml +-# app/views/user.haml +.row + .col-md-6 + = self.name + .col-md-6 + = self.age +``` + +You are nearly ready to go. Lets create a user instance and render the template +in the context of that user: + +```ruby +# app/application.rb +require 'opal' +require 'views/user' + +class User < Struct.new(:name, :age) +end + +ford = User.new('Ford Prefect', 42) +template = Template['views/user'] + +puts template.render(ford) +``` + +Note, when requiring haml templates you do not need to specify the `.haml` +extension. This code will print the rendered html to the console. If you +check it out, you should see it compiled into something like the following: + +```html +
+
+ Ford Prefect +
+
+ 42 +
+
+``` + +## ERB Templates + +Support for `erb` templates is built in directly to the opal gem and stdlib. +There is one caveat though when working with sprockets - it must have the +`.opalerb` file extension, instead of `.erb`. This is because sprockets has a +built in handler for `.erb` files. + +If we have the same user class as above, create an `app/views/user.opalerb` +file: + +```erb + +
+
<%= self.name %>
+
+``` + +Again, you must then require the template (without the `.opalerb` extension): + +```ruby +# app/application.rb +require 'opal' +require 'views/user' +``` + +And then you can access and render the template: + +```ruby +# app/application.rb + +template = Template['views/user'] +user = User.new('Ford Prefect') + +puts template.render(user) +# => "
...
" +``` diff --git a/docs/unsupported_features.md b/docs/unsupported_features.md new file mode 100644 index 00000000..979ef360 --- /dev/null +++ b/docs/unsupported_features.md @@ -0,0 +1,33 @@ +# Unsupported Features + +Opal does not support some language/runtime features of ruby. These are documented here when possible, as well as the reasons why they are not supported. + +#### Mutable Strings #### + +For performance and ease of runtime features, all strings in Opal are immutable, i.e. `#<<`, `#gsub!`, etc. do not exist. Also, symbols are just strings. There is no class, runtime or feature difference between Symbols and Strings. Their syntaxes can be used interchangeably. + +#### Regexp differences #### + +We are using JavaScript regular expressions. While we do translate a few of Ruby specific instructions like `\A` or `\z`, there are a lot of incompatibilities that you should be aware of - for example `$` and `^` don't match newlines like they do in Ruby. Support for features like named matches or lookahead/lookbehind is dependent on the JavaScript environment support for those. To support everything, we would need to [compile in the entire Ruby's regular expression engine](https://opalrb.com/blog/2021/06/26/webassembly-and-advanced-regexp-with-opal/) which is unfeasible at the current time. + +#### Integer / Float difference #### + +In Opal, both integers and floats belong to same class `Number` (using JavaScript native numbers). So `1 / 4` is `0.25` (not `0`) and `4.0 / 2` is `2` (not `2.0`). + +`Number` is a subclass of `Numeric`, like `Complex` and `Rational`. + +#### Encodings #### + +Encodings only have a very small implementation inside Opal. + +#### Threads #### + +JavaScript does not have a native `Thread` implementation, so they are not present inside Opal. There is a placeholder `Thread` class just to provide some small level of compatibility with libraries that expect it. It does not have any function. + +#### Frozen Objects #### + +Opal does not currently support frozen objects, but has placeholder methods to prevent other libraries breaking when expecting these methods. Opal could support frozen objects in the future once a similar implementation becomes available across JavaScript runtimes. + +#### Private, Public and Protected methods #### + +All methods in Opal are defined as `public` to avoid additional runtime overhead. `Module#private` and `Module#protected` exist as just placeholder methods and are no-op methods. diff --git a/docs/upgrading.md b/docs/upgrading.md new file mode 100644 index 00000000..5af0f585 --- /dev/null +++ b/docs/upgrading.md @@ -0,0 +1,22 @@ +# Upgrading from v0.8 to v0.9 + +## `Opal::Processor.load_asset_code` deprecated + +`Opal::Processor.load_asset_code(sprockets, name)` has been deprecated in favor of `Opal::Sprockets.load_asset(name, sprockets)`. + +## `$console.log` instead of `pp` + +Previously `pp` would have forwarded the object to JS own `console.log` but now just prints calling `.inspect` on it similarly to what `p` does. + +```ruby +require 'pp' +pp a: 1, b: {c: 3} +``` + +Now: + +```ruby +require 'console' +$console.log a: 1, b: {c: 3} +``` + diff --git a/docs/using_sprockets.md b/docs/using_sprockets.md new file mode 100644 index 00000000..edb4b3a6 --- /dev/null +++ b/docs/using_sprockets.md @@ -0,0 +1,92 @@ +# Opal & Sprockets + +The `opal-sprockets` gem adds sprockets support to Opal, providing a simple +`Opal::Sprockets::server` class to make it easy to get a rack server up and +running for trying out opal. This server will automatically recompile ruby +sources when they change, meaning you just need to refresh your page to autorun. + +## Getting setup + +Add `rack` & `opal-sprockets` to your `Gemfile`: + +```ruby +#Gemfile +source 'https://rubygems.org' + +gem 'rack' +gem 'opal-sprockets' +``` + +And install with `bundle install`. + +We need a directory to hold our opal code, so create `app/` and add a simple +demo script to `app/application.rb`: + +```ruby +# app/application.rb +require 'opal' + +puts "hello world" +``` + + +If we do not provide an HTML index, sprockets will generate one automatically; +however, it is often useful to override the default with a custom `erb` file: + +```html +<%# index.erb %> + + + + + opal server example + <%= javascript_include_tag @server.main %> + + + you've reached the custom index! + + +``` + +## Using Opal::Server + +`Opal::Server` can be run like any rack app, so just add a `config.ru` file: + +```ruby +# config.ru +require 'opal-sprockets' + +run Opal::Server.new { |s| + s.append_path 'app' + + s.main = 'application' + + # override the default index with our custom index + s.index_path = 'index.erb' +} +``` + +This rack app simply adds our `app/` directory to opal load path, and sets our +main file to `application`, which will be found inside `app/`. + +## Running the app + +Run `bundle exec rackup` and visit the page `http://localhost:9292` in any +browser. Observe the console to see the printed statement. + +You can just change `app/application.rb` and refresh the page to see any changes. + + +## Using an existing `sprockets` instance + +We only need to append Opal paths to the existing sprockets instance. + +```ruby +require 'sprockets' +environment = Sprockets::Environment.new + +require 'opal' +Opal.paths.each do |path| + environment.append_path path +end +``` diff --git a/examples/rack-esm/.gitignore b/examples/rack-esm/.gitignore new file mode 100644 index 00000000..a9a5aecf --- /dev/null +++ b/examples/rack-esm/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/examples/rack-esm/Gemfile b/examples/rack-esm/Gemfile new file mode 100644 index 00000000..24b6b40f --- /dev/null +++ b/examples/rack-esm/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gem 'rack' +gem 'opal', :path => '../../' +gem 'puma' \ No newline at end of file diff --git a/examples/rack-esm/app/application.rb b/examples/rack-esm/app/application.rb new file mode 100644 index 00000000..8aeefa03 --- /dev/null +++ b/examples/rack-esm/app/application.rb @@ -0,0 +1,27 @@ +require 'opal' +require 'user' +require 'opal/platform' + +module MyApp + class Application + def initialize + @user = User.new('Bob') + end + + def title + "#{@user.name} is #{:not unless @user.authenticated?} authenticated" + end + end +end + +$app = MyApp::Application.new + +require 'native' + +$$[:document][:title] = "#{$app.title}" + +bill = User.new('Bill') + +$$.alert "The user is named #{bill.name}." + +bill.authenticated? diff --git a/examples/rack-esm/app/user.rb b/examples/rack-esm/app/user.rb new file mode 100644 index 00000000..c138ea55 --- /dev/null +++ b/examples/rack-esm/app/user.rb @@ -0,0 +1,24 @@ +class User + def initialize(name) + puts "wow" + @name = name + end + + attr_reader :name + + def authenticated? + if admin? or special_permission? + true + else + raise "not authenticated" + end + end + + def admin? + @name == 'Bob' + end + + def special_permission? + false + end +end diff --git a/examples/rack-esm/config.ru b/examples/rack-esm/config.ru new file mode 100644 index 00000000..ad5d1d0b --- /dev/null +++ b/examples/rack-esm/config.ru @@ -0,0 +1,25 @@ +require 'bundler' +Bundler.require + +# Instructions: bundle in this directory +# then run `bundle exec rackup` to start the server +# and browse to http://localhost:9292 + +# a very small application that just tries to authenticate a user and fails +# it just writes to the console in the browser (no visible html) + +# with gems like opal-jquery or opal-browser you could manipulate the dom directly + +# the directory where the code is (add to opal load path ) +Opal.append_path 'app' + +# Enable ESM +Opal::Config.esm = true + +run Opal::SimpleServer.new { |s| + # the name of the ruby file to load. To use more files they must be required from here (see app) + s.main = 'application' + # need to set the index explicitly for opal server to pick it up + s.index_path = 'index.html.erb' +} + diff --git a/examples/rack-esm/index.html.erb b/examples/rack-esm/index.html.erb new file mode 100644 index 00000000..d2ec513b --- /dev/null +++ b/examples/rack-esm/index.html.erb @@ -0,0 +1,11 @@ + + + + + opal-sprockets demo + + <%= javascript_include_tag 'application' %> + + + + diff --git a/examples/rack/.gitignore b/examples/rack/.gitignore new file mode 100644 index 00000000..a9a5aecf --- /dev/null +++ b/examples/rack/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/examples/rack/Gemfile b/examples/rack/Gemfile new file mode 100644 index 00000000..24b6b40f --- /dev/null +++ b/examples/rack/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gem 'rack' +gem 'opal', :path => '../../' +gem 'puma' \ No newline at end of file diff --git a/examples/rack/app/application.rb b/examples/rack/app/application.rb new file mode 100644 index 00000000..8aeefa03 --- /dev/null +++ b/examples/rack/app/application.rb @@ -0,0 +1,27 @@ +require 'opal' +require 'user' +require 'opal/platform' + +module MyApp + class Application + def initialize + @user = User.new('Bob') + end + + def title + "#{@user.name} is #{:not unless @user.authenticated?} authenticated" + end + end +end + +$app = MyApp::Application.new + +require 'native' + +$$[:document][:title] = "#{$app.title}" + +bill = User.new('Bill') + +$$.alert "The user is named #{bill.name}." + +bill.authenticated? diff --git a/examples/rack/app/user.rb b/examples/rack/app/user.rb new file mode 100644 index 00000000..c138ea55 --- /dev/null +++ b/examples/rack/app/user.rb @@ -0,0 +1,24 @@ +class User + def initialize(name) + puts "wow" + @name = name + end + + attr_reader :name + + def authenticated? + if admin? or special_permission? + true + else + raise "not authenticated" + end + end + + def admin? + @name == 'Bob' + end + + def special_permission? + false + end +end diff --git a/examples/rack/config.ru b/examples/rack/config.ru new file mode 100644 index 00000000..f9003b80 --- /dev/null +++ b/examples/rack/config.ru @@ -0,0 +1,22 @@ +require 'bundler' +Bundler.require + +# Instructions: bundle in this directory +# then run `bundle exec rackup` to start the server +# and browse to http://localhost:9292 + +# a very small application that just tries to authenticate a user and fails +# it just writes to the console in the browser (no visible html) + +# with gems like opal-jquery or opal-browser you could manipulate the dom directly + +# the directory where the code is (add to opal load path ) +Opal.append_path 'app' + +run Opal::SimpleServer.new { |s| + # the name of the ruby file to load. To use more files they must be required from here (see app) + s.main = 'application' + # need to set the index explicitly for opal server to pick it up + s.index_path = 'index.html.erb' +} + diff --git a/examples/rack/index.html.erb b/examples/rack/index.html.erb new file mode 100644 index 00000000..d2ec513b --- /dev/null +++ b/examples/rack/index.html.erb @@ -0,0 +1,11 @@ + + + + + opal-sprockets demo + + <%= javascript_include_tag 'application' %> + + + + diff --git a/examples/sinatra/Gemfile b/examples/sinatra/Gemfile new file mode 100644 index 00000000..727002a2 --- /dev/null +++ b/examples/sinatra/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gem 'opal', :path => '../..' +gem 'opal-sprockets' +gem 'puma' # webrick has a bug with safari +gem 'sinatra' diff --git a/examples/sinatra/app/application.rb b/examples/sinatra/app/application.rb new file mode 100644 index 00000000..28e8f878 --- /dev/null +++ b/examples/sinatra/app/application.rb @@ -0,0 +1,9 @@ +require 'opal' + +def alert(msg) + `alert(msg)` + raise "an example exception with source-map powered backtrace" +end + +alert "Hi there!" + diff --git a/examples/sinatra/config.ru b/examples/sinatra/config.ru new file mode 100644 index 00000000..796886e9 --- /dev/null +++ b/examples/sinatra/config.ru @@ -0,0 +1,28 @@ +require 'opal/sprockets' +require 'sinatra' + +opal = Opal::Sprockets::Server.new {|s| + s.append_path 'app' + s.main = 'application' +} + +sprockets = opal.sprockets +prefix = '/assets' + +map prefix do + run sprockets +end + +get '/' do + <<-HTML + + + + + #{::Opal::Sprockets.javascript_include_tag('application', sprockets: sprockets, prefix: prefix, debug: true)} + + + HTML +end + +run Sinatra::Application diff --git a/exe/opal b/exe/opal new file mode 100755 index 00000000..a049475d --- /dev/null +++ b/exe/opal @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +# Error codes are taken from /usr/include/sysexits.h + +OriginalARGV = ARGV.dup + +require 'opal/cli_options' +options = Opal::CLIOptions.new +begin + options.parse! +rescue OptionParser::InvalidOption => e + $stderr.puts "#{$0}: #{e.message} (-h will show valid options)" + exit 64 +end + +require 'opal/cli' +options_hash = options.options +options_hash.merge!( + file: ARGF.file, + filename: ARGF.filename, + argv: ARGV.dup +) unless options_hash[:lib_only] +cli = Opal::CLI.new options_hash + +begin + cli.run + exit cli.exit_status || 0 +rescue Opal::CliRunners::RunnerError => e + $stderr.puts e.message + exit 72 +end diff --git a/exe/opal-build b/exe/opal-build new file mode 100755 index 00000000..499de4fd --- /dev/null +++ b/exe/opal-build @@ -0,0 +1,77 @@ +#!/usr/bin/env ruby + +require 'optparse' + +module Opal + class BuilderOptions < OptionParser + def initialize + @options = {} + + super do |opts| + opts.banner = 'Usage: opal-build [options] -- [libname]' + + opts.separator '' + opts.separator 'Options:' + + opts.on("-h", "--help", "Show this message") do + puts opts + exit + end + + opts.on('-g', '--gem GEM_NAME', String, + 'Adds the specified GEM_NAME lib dir to Opal\'s load path.', + 'E.g.: opal-build --gem erubis -- erubis`', + 'Will build erubis.rb from the regular "erubis" gem') do |g| + options[:gems] ||= [] + options[:gems] << g + end + + opts.on('-s', '--stub STUB', String) do |stub| + options[:stubs] ||= [] + options[:stubs] << stub + end + + opts.on('-r', '--require LIBRARY', String, + 'Require the library before executing your script', + 'E.g.: opal-build --require opal-browser browser`', + 'Will build browser.rb from the Opal gem opal-browser') do |library| + options[:requires] ||= [] + options[:requires] << library + end + + opts.on('-o', '--output FILE', String, + 'Write the built lib to a file (defaults to STDOUT)') do |file| + options[:output] = file + end + end + end + + attr_reader :options + end +end + +option_parser = Opal::BuilderOptions.new +option_parser.parse! + +if ARGV.empty? + puts option_parser +else + require 'opal' + options = option_parser.options + + if options[:gems] + require 'rubygems' + options[:gems].each { |gem_name| Opal.use_gem gem_name } + end + + if options[:requires] + options[:requires].each { |required_lib| require required_lib } + end + + lib_name = ARGV.first + + output = options[:output] ? File.open(options[:output], 'w') : $stdout + output.puts Opal::Builder.build(lib_name.dup.untaint) +end + + diff --git a/exe/opal-repl b/exe/opal-repl new file mode 100755 index 00000000..d6724ad3 --- /dev/null +++ b/exe/opal-repl @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +exec "#{__dir__}/opal", '--repl', *ARGV diff --git a/lib/opal.rb b/lib/opal.rb new file mode 100644 index 00000000..dbe7a628 --- /dev/null +++ b/lib/opal.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require 'opal/requires' diff --git a/lib/opal/ast/builder.rb b/lib/opal/ast/builder.rb new file mode 100644 index 00000000..a5143a51 --- /dev/null +++ b/lib/opal/ast/builder.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'opal/ast/node' +require 'parser/ruby31' + +module Opal + module AST + class Builder < ::Parser::Builders::Default + self.emit_lambda = true + + def n(type, children, location) + ::Opal::AST::Node.new(type, children, location: location) + end + end + end +end diff --git a/lib/opal/ast/node.rb b/lib/opal/ast/node.rb new file mode 100644 index 00000000..c1b67c95 --- /dev/null +++ b/lib/opal/ast/node.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'ast' +require 'parser/ast/node' + +module Opal + module AST + class Node < ::Parser::AST::Node + attr_reader :meta + + def assign_properties(properties) + if meta = properties[:meta] + meta = meta.dup if meta.frozen? + @meta.merge!(meta) + else + @meta ||= {} + end + + super + end + + def line + loc.line if loc + end + + def column + loc.column if loc + end + end + end +end diff --git a/lib/opal/builder.rb b/lib/opal/builder.rb new file mode 100644 index 00000000..3c9c8a89 --- /dev/null +++ b/lib/opal/builder.rb @@ -0,0 +1,264 @@ +# frozen_string_literal: true + +require 'opal/path_reader' +require 'opal/paths' +require 'opal/config' +require 'opal/cache' +require 'set' + +module Opal + class Builder + # The registered processors + def self.processors + @processors ||= [] + end + + # All the extensions supported by registered processors + def self.extensions + @extensions ||= [] + end + + # @public + # Register a builder processor and the supported extensions. + # A processor will respond to: + # + # ## `#requires` + # An array of string containing the logic paths of required assets + # + # ## `#required_trees` + # An array of string containing the logic paths of required directories + # + # ## `#autoloads` + # An array of entities that are autoloaded and their compile-time load failure can + # be safely ignored + # + # ## `#to_s` + # The processed source + # + # ## `#source_map` + # An instance of `::Opal::SourceMap::File` representing the processd asset's source + # map. + # + # ## `.new(source, filename, compiler_options)` + # The processor will be instantiated passing: + # - the unprocessed source + # - the asset's filename + # - Opal's compiler options + # + # ## `.match?(path)` + # The processor is able to recognize paths suitable for its type of + # processing. + # + def self.register_processor(processor, processor_extensions) + return if processors.include?(processor) + processors << processor + processor_extensions.each { |ext| extensions << ext } + end + + + + class MissingRequire < LoadError + end + + class ProcessorNotFound < LoadError + end + + def initialize(options = nil) + (options || {}).each_pair do |k, v| + public_send("#{k}=", v) + end + + @stubs ||= [] + @preload ||= [] + @processors ||= ::Opal::Builder.processors + @path_reader ||= PathReader.new(Opal.paths, extensions.map { |e| [".#{e}", ".js.#{e}"] }.flatten) + @prerequired ||= [] + @compiler_options ||= Opal::Config.compiler_options + @missing_require_severity ||= Opal::Config.missing_require_severity + @cache ||= Opal.cache + + @processed = [] + end + + def self.build(*args, &block) + new.build(*args, &block) + end + + def build(path, options = {}) + build_str(source_for(path), path, options) + end + + # Retrieve the source for a given path the same way #build would do. + def source_for(path) + read(path, false) + end + + def build_str(source, rel_path, options = {}) + return if source.nil? + abs_path = expand_path(rel_path) + rel_path = expand_ext(rel_path) + asset = processor_for(source, rel_path, abs_path, false, options) + requires = preload + asset.requires + tree_requires(asset, abs_path) + requires.map { |r| process_require(r, asset.autoloads, options) } + processed << asset + self + rescue MissingRequire => error + raise error, "A file required by #{rel_path.inspect} wasn't found.\n#{error.message}", error.backtrace + end + + def build_require(path, options = {}) + process_require(path, [], options) + end + + def initialize_copy(other) + super + @stubs = other.stubs.dup + @preload = other.preload.dup + @processors = other.processors.dup + @path_reader = other.path_reader.dup + @prerequired = other.prerequired.dup + @compiler_options = other.compiler_options.dup + @missing_require_severity = other.missing_require_severity.to_sym + @processed = other.processed.dup + end + + def to_s + processed.map(&:to_s).join("\n") + end + + def source_map + ::Opal::SourceMap::Index.new(processed.map(&:source_map), join: "\n") + end + + def append_paths(*paths) + path_reader.append_paths(*paths) + end + + include UseGem + + attr_reader :processed + + attr_accessor :processors, :path_reader, :stubs, :prerequired, :preload, + :compiler_options, :missing_require_severity, :cache + + private + + def tree_requires(asset, asset_path) + dirname = asset_path.to_s.empty? ? Pathname.pwd : Pathname(asset_path).expand_path.dirname + abs_base_paths = path_reader.paths.map { |p| File.expand_path(p) } + + asset.required_trees.flat_map do |tree| + abs_tree_path = dirname.join(tree).expand_path.to_s + abs_base_path = abs_base_paths.find { |p| abs_tree_path.start_with?(p) } + + if abs_base_path + abs_base_path = Pathname(abs_base_path) + entries_glob = Pathname(abs_tree_path).join('**', "*{.js,}.{#{extensions.join ','}}") + + Pathname.glob(entries_glob).map { |file| file.relative_path_from(abs_base_path).to_s } + else + [] # the tree is not part of any known base path + end + end + end + + def processor_for(source, rel_path, abs_path, autoload, options) + processor = processors.find { |p| p.match? abs_path } + + if !processor && !autoload + raise(ProcessorNotFound, "can't find processor for rel_path: " \ + "#{rel_path.inspect}, "\ + "abs_path: #{abs_path.inspect}, "\ + "source: #{source.inspect}, "\ + "processors: #{processors.inspect}" + ) + end + + options = options.merge(cache: cache) + + processor.new(source, rel_path, @compiler_options.merge(options)) + end + + def read(path, autoload) + path_reader.read(path) || begin + print_list = ->(list) { "- #{list.join("\n- ")}\n" } + message = "can't find file: #{path.inspect} in:\n" + + print_list[path_reader.paths] + + "\nWith the following extensions:\n" + + print_list[path_reader.extensions] + + "\nAnd the following processors:\n" + + print_list[processors] + + unless autoload + case missing_require_severity + when :error then raise MissingRequire, message + when :warning then warn message + when :ignore then # noop + end + end + + nil + end + end + + def process_require(rel_path, autoloads, options) + return if prerequired.include?(rel_path) + return if already_processed.include?(rel_path) + already_processed << rel_path + + autoload = autoloads.include? rel_path + + source = stub?(rel_path) ? '' : read(rel_path, autoload) + + # The handling is delegated to the runtime + return if source.nil? + + abs_path = expand_path(rel_path) + rel_path = expand_ext(rel_path) + asset = processor_for(source, rel_path, abs_path, autoload, options.merge(requirable: true)) + process_requires( + rel_path, + asset.requires + tree_requires(asset, abs_path), + asset.autoloads, + options + ) + processed << asset + end + + def expand_ext(path) + abs_path = path_reader.expand(path) + + if abs_path + File.join( + File.dirname(path), + File.basename(abs_path) + ) + else + path + end + end + + def expand_path(path) + return if stub?(path) + (path_reader.expand(path) || File.expand_path(path)).to_s + end + + def process_requires(rel_path, requires, autoloads, options) + requires.map { |r| process_require(r, autoloads, options) } + rescue MissingRequire => error + raise error, "A file required by #{rel_path.inspect} wasn't found.\n#{error.message}", error.backtrace + end + + def already_processed + @already_processed ||= Set.new + end + + def stub?(path) + stubs.include?(path) + end + + def extensions + ::Opal::Builder.extensions + end + end +end diff --git a/lib/opal/builder_processors.rb b/lib/opal/builder_processors.rb new file mode 100644 index 00000000..22b2ca8f --- /dev/null +++ b/lib/opal/builder_processors.rb @@ -0,0 +1,146 @@ +# frozen_string_literal: true + +require 'opal/compiler' +require 'opal/erb' + +module Opal + module BuilderProcessors + class Processor + def initialize(source, filename, options = {}) + source += "\n" unless source.end_with?("\n") + @source, @filename, @options = source, filename, options.dup + @cache = @options.delete(:cache) { Opal.cache } + @requires = [] + @required_trees = [] + @autoloads = [] + end + attr_reader :source, :filename, :options, :requires, :required_trees, :autoloads + + def to_s + source.to_s + end + + class << self + attr_reader :extensions + + def handles(*extensions) + @extensions = extensions + matches = extensions.join('|') + matches = "(#{matches})" unless extensions.size == 1 + @match_regexp = Regexp.new "\\.#{matches}#{REGEXP_END}" + + ::Opal::Builder.register_processor(self, extensions) + nil + end + + def match?(other) + other.is_a?(String) && other.match(match_regexp) + end + + def match_regexp + @match_regexp || raise(NotImplementedError) + end + end + + def mark_as_required(filename) + "Opal.loaded([#{filename.to_s.inspect}]);" + end + end + + class JsProcessor < Processor + handles :js + + ManualFragment = Struct.new(:line, :column, :code, :source_map_name) + + def source_map + @source_map ||= begin + manual_fragments = source.each_line.with_index.map do |line_source, index| + column = line_source.index(/\S/) + line = index + 1 + ManualFragment.new(line, column, line_source, nil) + end + + ::Opal::SourceMap::File.new(manual_fragments, filename, source) + end + end + + def source + @source.to_s + mark_as_required(@filename) + end + end + + class RubyProcessor < Processor + handles :rb, :opal + + def source + compiled.result + end + + def source_map + compiled.source_map + end + + def compiled + @compiled ||= Opal::Cache.fetch(@cache, cache_key) do + compiler = compiler_for(@source, file: @filename) + compiler.compile + compiler + end + end + + def cache_key + [self.class, @filename, @source, @options] + end + + def compiler_for(source, options = {}) + ::Opal::Compiler.new(source, @options.merge(options)) + end + + def requires + compiled.requires + end + + def required_trees + compiled.required_trees + end + + def autoloads + compiled.autoloads + end + + # Also catch a files with missing extensions and nil. + def self.match?(other) + super || File.extname(other.to_s) == '' + end + end + + class OpalERBProcessor < RubyProcessor + handles :opalerb + + def initialize(*args) + super + @source = prepare(@source, @filename) + end + + def requires + ['erb'] + super + end + + private + + def prepare(source, path) + ::Opal::ERB::Compiler.new(source, path).prepared_source + end + end + + class ERBProcessor < Processor + handles :erb + + def source + result = ::ERB.new(@source.to_s).result + module_name = ::Opal::Compiler.module_name(@filename) + "Opal.modules[#{module_name.inspect}] = function() {#{result}};" + end + end + end +end diff --git a/lib/opal/cache.rb b/lib/opal/cache.rb new file mode 100644 index 00000000..7a5d02ce --- /dev/null +++ b/lib/opal/cache.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'opal/paths' +require 'digest/sha2' unless RUBY_ENGINE == 'opal' + +if RUBY_ENGINE != 'opal' + require 'opal/cache/file_cache' +end + +module Opal + # A Sprockets-compatible cache, for example an instance of + # Opal::Cache::FileCache or Opal::Cache::NullCache. + singleton_class.attr_writer :cache + + def self.cache + @cache ||= + if RUBY_ENGINE == 'opal' || ENV['OPAL_CACHE_DISABLE'] || !Cache::FileCache.find_dir + Cache::NullCache.new + else + Cache::FileCache.new + end + end + + module Cache + class NullCache + def fetch(*) + yield + end + end + + module_function + + def fetch(cache, key, &block) + # Extension to the Sprockets API of Cache, if a cache responds + # to #fetch, then we call it instead of using #get and #set. + return cache.fetch(key, &block) if cache.respond_to? :fetch + + key = digest(key.join('/')) + '-' + runtime_key + + data = cache.get(key) + + data || begin + compiler = yield + cache.set(key, compiler) unless compiler.dynamic_cache_result + compiler + end + end + + def runtime_key + @runtime_key ||= begin + # We want to ensure the compiler and any Gemfile/gemspec (for development) + # stays untouched + opal_path = File.expand_path('..', Opal.gem_dir) + files = Dir["#{opal_path}/{Gemfile*,*.gemspec,lib/**/*}"] + + # Also check if parser wasn't changed: + files += $LOADED_FEATURES.grep(%r{lib/(parser|ast)}) + + digest [ + files.sort.map { |f| "#{f}:#{File.size(f)}:#{File.mtime(f).to_f}" }, + RUBY_VERSION, + RUBY_PATCHLEVEL + ].join('/') + end + end + + def digest(string) + ::Digest::SHA256.hexdigest(string)[-32..-1].to_i(16).to_s(36) + end + end +end diff --git a/lib/opal/cache/file_cache.rb b/lib/opal/cache/file_cache.rb new file mode 100644 index 00000000..008d9664 --- /dev/null +++ b/lib/opal/cache/file_cache.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'fileutils' +require 'zlib' + +module Opal + module Cache + class FileCache + def initialize(dir: nil, max_size: nil) + @dir = dir || self.class.find_dir + # Store at most 32MB of cache - de facto this 32MB is larger, + # as we don't account for inode size for instance. In fact, it's + # about 50M. Also we run this check before anything runs, so things + # may go up to 64M or even larger. + @max_size = max_size || 32 * 1024 * 1024 + + tidy_up_cache + end + + def set(key, data) + file = cache_filename_for(key) + + out = Marshal.dump(data) + out = Zlib.gzip(out, level: 9) + File.binwrite(file, out) + end + + def get(key) + file = cache_filename_for(key) + + if File.exist?(file) + FileUtils.touch(file) + out = File.binread(file) + out = Zlib.gunzip(out) + Marshal.load(out) # rubocop:disable Security/MarshalLoad + end + rescue Zlib::GzipFile::Error + nil + end + + # Remove cache entries that overflow our cache limit... and which + # were used least recently. + private def tidy_up_cache + entries = Dir[@dir + '/*.rbm.gz'] + entries_stats = entries.map { |entry| [entry, File.stat(entry)] } + + size_sum = entries_stats.map { |_entry, stat| stat.size }.sum + return unless size_sum > @max_size + + # First, we try to get the oldest files first. + # Then, what's more important, is that we try to get the least + # recently used files first. Filesystems with relatime or noatime + # will get this wrong, but it doesn't matter that much, because + # the previous sort got things "maybe right". + entries_stats = entries_stats.sort_by { |_entry, stat| [stat.mtime, stat.atime] } + + entries_stats.each do |entry, stat| + size_sum -= stat.size + File.unlink(entry) + + # We don't need to work this out anymore - we reached our goal. + break unless size_sum > @max_size + end + rescue Errno::ENOENT + # Do nothing, this comes from multithreading. We will tidy up at + # the next chance. + nil + end + + # This complex piece of code tries to check if we can robustly mkdir_p a directory. + def self.dir_writable?(*paths) + dir = nil + paths = paths.reduce([]) do |a, b| + [*a, dir = a.last ? File.expand_path(b, a.last) : b] + end + + File.exist?(paths.first) && + paths.reverse.all? do |i| + !File.exist?(i) || (File.directory?(i) && File.writable?(i)) + end + + dir + end + + def self.find_dir + @find_dir ||= case + # Try to write cache into a directory pointed by an environment variable if present + when dir = ENV['OPAL_CACHE_DIR'] + FileUtils.mkdir_p(dir) + dir + # Otherwise, we write to the place where Opal is installed... + # I don't think it's a good location to store cache, so many things can go wrong. + # when dir = dir_writable?(Opal.gem_dir, '..', 'tmp', 'cache') + # FileUtils.mkdir_p(dir) + # FileUtils.chmod(0o700, dir) + # dir + # Otherwise, ~/.cache/opal... + when dir = dir_writable?(Dir.home, '.cache', 'opal') + FileUtils.mkdir_p(dir) + FileUtils.chmod(0o700, dir) + dir + # Only /tmp is writable... or isn't it? + when (dir = dir_writable?('/tmp', "opal-cache-#{ENV['USER']}")) && File.sticky?('/tmp') + FileUtils.mkdir_p(dir) + FileUtils.chmod(0o700, dir) + dir + # No way... we can't write anywhere... + else + warn "Couldn't find a writable path to store Opal cache. " \ + 'Try setting OPAL_CACHE_DIR environment variable' + nil + end + end + + private def cache_filename_for(key) + "#{@dir}/#{key}.rbm.gz" + end + end + end +end diff --git a/lib/opal/cli.rb b/lib/opal/cli.rb new file mode 100644 index 00000000..67489ecd --- /dev/null +++ b/lib/opal/cli.rb @@ -0,0 +1,188 @@ +# frozen_string_literal: true + +require 'opal/requires' +require 'opal/builder' +require 'opal/cli_runners' + +module Opal + class CLI + attr_reader :options, :file, :compiler_options, :evals, :load_paths, :argv, + :output, :requires, :rbrequires, :gems, :stubs, :verbose, :runner_options, + :preload, :filename, :debug, :no_exit, :lib_only, :missing_require_severity, + :no_cache + + class << self + attr_accessor :stdout + end + + def initialize(options = nil) + options ||= {} + + # Runner + @runner_type = options.delete(:runner) || :nodejs + @runner_options = options.delete(:runner_options) || {} + + @options = options + @sexp = options.delete(:sexp) + @repl = options.delete(:repl) + @file = options.delete(:file) + @no_exit = options.delete(:no_exit) + @lib_only = options.delete(:lib_only) + @argv = options.delete(:argv) { [] } + @evals = options.delete(:evals) { [] } + @load_paths = options.delete(:load_paths) { [] } + @gems = options.delete(:gems) { [] } + @stubs = options.delete(:stubs) { [] } + @preload = options.delete(:preload) { [] } + @output = options.delete(:output) { self.class.stdout || $stdout } + @verbose = options.delete(:verbose) { false } + @debug = options.delete(:debug) { false } + @filename = options.delete(:filename) { @file && @file.path } + @requires = options.delete(:requires) { [] } + @rbrequires = options.delete(:rbrequires) { [] } + @no_cache = options.delete(:no_cache) { false } + + @debug_source_map = options.delete(:debug_source_map) { false } + + @missing_require_severity = options.delete(:missing_require_severity) { Opal::Config.missing_require_severity } + + @requires.unshift('opal') unless options.delete(:skip_opal_require) + + @compiler_options = Hash[ + *compiler_option_names.map do |option| + key = option.to_sym + next unless options.key? key + value = options.delete(key) + [key, value] + end.compact.flatten + ] + + raise ArgumentError, 'no libraries to compile' if @lib_only && @requires.empty? + raise ArgumentError, 'no runnable code provided (evals or file)' if @evals.empty? && @file.nil? && !@lib_only + raise ArgumentError, "can't accept evals or file in `library only` mode" if (@evals.any? || @file) && @lib_only + raise ArgumentError, "unknown options: #{options.inspect}" unless @options.empty? + end + + def run + return show_sexp if @sexp + return debug_source_map if @debug_source_map + return run_repl if @repl + + @exit_status = runner.call( + options: runner_options, + output: output, + argv: argv, + builder: builder, + ) + end + + def runner + CliRunners[@runner_type] || + raise(ArgumentError, "unknown runner: #{@runner_type.inspect}") + end + + def run_repl + require 'opal/repl' + + repl = REPL.new + repl.run(OriginalARGV) + end + + attr_reader :exit_status + + def builder + @builder ||= create_builder + end + + def create_builder + rbrequires.each(&Kernel.method(:require)) + + builder = Opal::Builder.new( + stubs: stubs, + compiler_options: compiler_options, + missing_require_severity: missing_require_severity, + ) + + # --no-cache + builder.cache = Opal::Cache::NullCache.new if no_cache + + # --include + builder.append_paths(*load_paths) + + # --gem + gems.each { |gem_name| builder.use_gem gem_name } + + # --require + requires.each { |required| builder.build(required) } + + # --preload + preload.each { |path| builder.build_require(path) } + + # --verbose + builder.build_str '$VERBOSE = true', '(flags)' if verbose + + # --debug + builder.build_str '$DEBUG = true', '(flags)' if debug + + # --eval / stdin / file + evals_or_file { |source, filename| builder.build_str(source, filename) } + + # --no-exit + builder.build_str '::Kernel.exit', '(exit)' unless no_exit + + builder + end + + def show_sexp + evals_or_file do |contents, filename| + buffer = ::Opal::Parser::SourceBuffer.new(filename) + buffer.source = contents + sexp = Opal::Parser.default_parser.parse(buffer) + output.puts sexp.inspect + end + end + + def debug_source_map + evals_or_file do |contents, filename| + compiler = Opal::Compiler.new(contents, file: filename, **compiler_options) + + compiler.compile + + result = compiler.result + source_map = compiler.source_map.to_json + + b64 = [result, source_map, contents].map { |i| Base64.strict_encode64(i) }.join(',') + + output.puts "https://sokra.github.io/source-map-visualization/#base64,#{b64}" + end + end + + def compiler_option_names + %w[ + method_missing + arity_check + dynamic_require_severity + source_map_enabled + irb_enabled + inline_operators + enable_source_location + use_strict + parse_comments + esm + ] + end + + # Internal: Yields a string of source code and the proper filename for either + # evals, stdin or a filepath. + def evals_or_file + # --library + return if lib_only + + if evals.any? + yield evals.join("\n"), '-e' + elsif file && (filename != '-' || evals.empty?) + yield file.read, filename + end + end + end +end diff --git a/lib/opal/cli_options.rb b/lib/opal/cli_options.rb new file mode 100644 index 00000000..462c275c --- /dev/null +++ b/lib/opal/cli_options.rb @@ -0,0 +1,219 @@ +# frozen_string_literal: true + +require 'optparse' +require 'opal/cli_runners' + +module Opal + class CLIOptions < OptionParser + def initialize + super + @options = {} + + self.banner = 'Usage: opal [options] -- [programfile]' + + separator '' + + on('-v', '--verbose', 'print version number, then turn on verbose mode') do + print_version + exit if ARGV.empty? + options[:verbose] = true + end + + on('--verbose', 'turn on verbose mode (set $VERBOSE to true)') do + options[:verbose] = true + end + + on('-d', '--debug', 'turn on debug mode (set $DEBUG to true)') do + options[:debug] = true + end + + on('--version', 'Print the version') do + print_version + exit + end + + on('--repl', 'Run the Opal REPL') do + options[:repl] = true + end + + on('-h', '--help', 'Show this message') do + puts self + exit + end + + section 'Basic Options:' + + on('-I', '--include DIR', 'Append a load path (may be used more than once)') do |i| + options[:load_paths] ||= [] + options[:load_paths] << i + end + + on('-e', '--eval SOURCE', String, + 'One line of script. Several -e\'s allowed. Omit [programfile]' + ) do |source| + options[:evals] ||= [] + options[:evals] << source + end + + on('-r', '--require LIBRARY', String, + 'Require the library before executing your script' + ) do |library| + options[:requires] ||= [] + options[:requires] << library + end + + on('-q', '--rbrequire LIBRARY', String, + 'Require the library in Ruby context before compiling' + ) do |library| + options[:rbrequires] ||= [] + options[:rbrequires] << library + end + + on('-s', '--stub FILE', String, 'Stubbed files will be compiled as empty files') do |stub| + options[:stubs] ||= [] + options[:stubs] << stub + end + + on('-p', '--preload FILE', String, 'Preloaded files will be prepared for dynamic requires') do |stub| + options[:preload] ||= [] + options[:preload] << stub + end + + on('-g', '--gem GEM_NAME', String, 'Adds the specified GEM_NAME to Opal\'s load path.') do |g| + options[:gems] ||= [] + options[:gems] << g + end + + section 'Running Options:' + + on('--sexp', 'Show Sexps') do + options[:sexp] = true + end + + on('--debug-source-map', 'Debug source map') do + options[:debug_source_map] = true + end + + on('-c', '--compile', 'Compile to JavaScript') do + options[:runner] = :compiler + end + + on('-R', '--runner RUNNER', Opal::CliRunners.to_h.keys, "Choose the runner: nodejs (default), #{(Opal::CliRunners.to_h.keys - [:nodejs]).join(', ')}") do |runner| + options[:runner] = runner.to_sym + end + + on('--runner-options JSON', 'Set options specific to the selected runner as a JSON string (e.g. port for server)') do |json_options| + require 'json' + runner_options = JSON.parse(json_options, symbolize_names: true) + options[:runner_options] ||= {} + options[:runner_options].merge!(runner_options) + end + + on('--server-port PORT', '(deprecated, use --runner-options) Set the port for the server runner (default port: 3000)') do |port| + options[:runner_options] ||= {} + options[:runner_options][:port] = port.to_i + end + + on('-E', '--no-exit', 'Do not append a Kernel#exit at the end of file') do + options[:no_exit] = true + end + + section 'Compilation Options:' + + on('-M', '--no-method-missing', 'Disable method missing') do + options[:method_missing] = false + end + + on('-O', '--no-opal', 'Disable implicit `require "opal"`') do + options[:skip_opal_require] = true + end + + on('-A', '--arity-check', 'Enable arity check') do + options[:arity_check] = true + end + + on('-V', 'Enable inline Operators') do + options[:inline_operators] = true + end + + dynamic_require_levels = %w[error warning ignore] + on('-D', '--dynamic-require LEVEL', dynamic_require_levels, + 'Set level of dynamic require severity.', + "(default: error, values: #{dynamic_require_levels.join(', ')})" + ) do |level| + options[:dynamic_require_severity] = level.to_sym + end + + missing_require_levels = %w[error warning ignore] + on('--missing-require LEVEL', missing_require_levels, + 'Set level of missing require severity.', + "(default: error, values: #{missing_require_levels.join(', ')})" + ) do |level| + options[:missing_require_severity] = level.to_sym + end + + on('-P', '--map FILE', 'Output path to FILE') do |file| + options[:runner_options] ||= {} + options[:runner_options][:map_file] = file + end + + on('--no-source-map', "Don't append source map to a compiled file") do + options[:runner_options] ||= {} + options[:runner_options][:no_source_map] = true + end + + on('-F', '--file FILE', 'Set filename for compiled code') do |file| + options[:file] = file + end + + on('-L', '--library', 'Compile only required libraries. Omit [programfile] and [-e]. Assumed [-cOE].') do + options[:lib_only] = true + options[:no_exit] = true + options[:compile] = true + options[:skip_opal_require] = true + end + + on('--irb', 'Enable IRB var mode') do + options[:irb] = true + end + + on('--enable-source-location', 'Compiles source location for each method definition.') do + options[:enable_source_location] = true + end + + on('--use-strict', 'Enables JavaScript\'s strict mode (i.e., adds \'use strict\'; statement)') do + options[:use_strict] = true + end + + on('--parse-comments', 'Compiles comments for each method definition.') do + options[:parse_comments] = true + end + + on('--no-cache', 'Disable filesystem cache') do + options[:no_cache] = true + end + + on('--esm', 'Wraps compiled bundle as for ES6 module(requires -c or -L)') do + options[:esm] = true + end + + separator '' + end + + attr_reader :options + + + private + + def print_version + require 'opal/version' + puts "Opal v#{Opal::VERSION}" + end + + def section(title) + separator '' + separator title + separator '' + end + end +end diff --git a/lib/opal/cli_runners.rb b/lib/opal/cli_runners.rb new file mode 100644 index 00000000..288d0da1 --- /dev/null +++ b/lib/opal/cli_runners.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module Opal + # `Opal::CliRunners` is the register in which JavaScript runners can be + # defined for use by `Opal::CLI`. Runners will be called via the `#call` + # method and passed a Hash containing the following keys: + # + # + # - `options`: a hash of options for the runner + # - `output`: an IO-like object responding to `#write` and `#puts` + # - `argv`: is the arguments vector coming from the CLI that is being + # forwarded to the program + # - `builder`: the current instance of Opal::Builder + # + # Runners can be registered using `#register_runner(name, runner)`. + # + module CliRunners + class RunnerError < StandardError + end + + @register = {} + + def self.[](name) + @register[name.to_sym] + end + + # @private + def self.[]=(name, runner) + warn "Overwriting Opal CLI runner: #{name}" if @register.key? name.to_sym + + @register[name.to_sym] = runner + end + private_class_method :[]= + + def self.to_h + @register + end + + # @param name [Symbol] the name at which the runner can be reached + # @param runner [#call] a callable object that will act as the "runner" + # @param runner [Symbol] a constant name that once autoloaded will point to + # a callable. + # @param path [nil,String] a path for setting up autoload on the constant + def self.register_runner(name, runner, path = nil) + autoload runner, path if path + + if runner.respond_to?(:call) + self[name] = runner + else + self[name] = ->(data) { const_get(runner).call(data) } + end + + nil + end + + # Alias a runner name + def self.alias_runner(new_name, old_name) + self[new_name.to_sym] = self[old_name.to_sym] + + nil + end + + register_runner :applescript, :Applescript, 'opal/cli_runners/applescript' + register_runner :chrome, :Chrome, 'opal/cli_runners/chrome' + register_runner :compiler, :Compiler, 'opal/cli_runners/compiler' + register_runner :nashorn, :Nashorn, 'opal/cli_runners/nashorn' + register_runner :nodejs, :Nodejs, 'opal/cli_runners/nodejs' + register_runner :gjs, :Gjs, 'opal/cli_runners/gjs' + register_runner :quickjs, :Quickjs, 'opal/cli_runners/quickjs' + register_runner :miniracer, :MiniRacer, 'opal/cli_runners/mini_racer' + register_runner :server, :Server, 'opal/cli_runners/server' + + alias_runner :osascript, :applescript + alias_runner :node, :nodejs + end +end diff --git a/lib/opal/cli_runners/applescript.rb b/lib/opal/cli_runners/applescript.rb new file mode 100644 index 00000000..4d3e95c0 --- /dev/null +++ b/lib/opal/cli_runners/applescript.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'opal/cli_runners/system_runner' + +module Opal + module CliRunners + class Applescript + def self.call(data) + unless system('which osalang > /dev/null') + raise MissingJavaScriptSupport, 'JavaScript Automation is only supported by OS X Yosemite and above.' + end + + SystemRunner.call(data) do |tempfile| + tempfile.puts "'';" # OSAScript will output the last thing + ['osascript', '-l', 'JavaScript', tempfile.path, *data[:argv]] + end + rescue Errno::ENOENT + raise MissingAppleScript, 'AppleScript is only available on Mac OS X.' + end + + class MissingJavaScriptSupport < RunnerError + end + + class MissingAppleScript < RunnerError + end + end + end +end diff --git a/lib/opal/cli_runners/chrome.rb b/lib/opal/cli_runners/chrome.rb new file mode 100644 index 00000000..598512a6 --- /dev/null +++ b/lib/opal/cli_runners/chrome.rb @@ -0,0 +1,182 @@ +# frozen_string_literal: true + +require 'shellwords' +require 'socket' +require 'timeout' +require 'tmpdir' +require 'rbconfig' + +module Opal + module CliRunners + class Chrome + SCRIPT_PATH = File.expand_path('chrome_cdp_interface.rb', __dir__).freeze + + DEFAULT_CHROME_HOST = 'localhost' + DEFAULT_CHROME_PORT = 9222 + + def self.call(data) + runner = new(data) + runner.run + end + + def initialize(data) + builder = data[:builder] + options = data[:options] + argv = data[:argv] + + if argv && argv.any? + warn "warning: ARGV is not supported by the Chrome runner #{argv.inspect}" + end + + @output = options.fetch(:output, $stdout) + @builder = builder + end + + attr_reader :output, :exit_status, :builder + + def run + mktmpdir do |dir| + with_chrome_server do + prepare_files_in(dir) + + env = { + 'CHROME_HOST' => chrome_host, + 'CHROME_PORT' => chrome_port.to_s, + 'NODE_PATH' => File.join(__dir__, 'node_modules') + } + + cmd = [ + RbConfig.ruby, + "#{__dir__}/../../../exe/opal", + '--no-exit', + '-I', __dir__, + '-r', 'source-map-support-node', + SCRIPT_PATH, + dir, + ] + + Kernel.exec(env, *cmd) + end + end + end + + private + + def prepare_files_in(dir) + js = builder.to_s + map = builder.source_map.to_json + stack = File.read("#{__dir__}/source-map-support-browser.js") + + # Chrome can't handle huge data passed to `addScriptToEvaluateOnLoad` + # https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/U5qyeX_ydBo + # The only way is to create temporary files and pass them to chrome. + File.write("#{dir}/index.js", js) + File.write("#{dir}/source-map-support.js", stack) + File.write("#{dir}/index.html", <<~HTML) + + + + + + + + HTML + end + + def chrome_host + ENV['CHROME_HOST'] || DEFAULT_CHROME_HOST + end + + def chrome_port + ENV['CHROME_PORT'] || DEFAULT_CHROME_PORT + end + + def with_chrome_server + if chrome_server_running? + yield + else + run_chrome_server { yield } + end + end + + def run_chrome_server + raise 'Chrome server can be started only on localhost' if chrome_host != DEFAULT_CHROME_HOST + + # Disable web security with "--disable-web-security" flag to be able to do XMLHttpRequest (see test_openuri.rb) + chrome_server_cmd = %{#{chrome_executable.shellescape} \ + --headless \ + --disable-web-security \ + --remote-debugging-port=#{chrome_port} \ + #{ENV['CHROME_OPTS']}} + + chrome_pid = Process.spawn(chrome_server_cmd) + + Timeout.timeout(10) do + loop do + break if chrome_server_running? + sleep 0.5 + end + end + + yield + rescue Timeout::Error + puts 'Failed to start chrome server' + puts 'Make sure that you have it installed and that its version is > 59' + exit(1) + ensure + if Gem.win_platform? && chrome_pid + Process.kill('KILL', chrome_pid) unless system("taskkill /f /t /pid #{chrome_pid} >NUL 2>NUL") + elsif chrome_pid + Process.kill('HUP', chrome_pid) + end + end + + def chrome_server_running? + puts "Connecting to #{chrome_host}:#{chrome_port}..." + TCPSocket.new(chrome_host, chrome_port).close + true + rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL + false + end + + def chrome_executable + ENV['GOOGLE_CHROME_BINARY'] || + case RbConfig::CONFIG['host_os'] + when /bccwin|cygwin|djgpp|mingw|mswin|wince/ + [ + 'C:/Program Files/Google/Chrome Dev/Application/chrome.exe', + 'C:/Program Files/Google/Chrome/Application/chrome.exe' + ].each do |path| + next unless File.exist? path + return path + end + when /darwin|mac os/ + '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' + else + %w[ + google-chrome-stable + chromium + chromium-freeworld + chromium-browser + ].each do |name| + next unless system('sh', '-c', "command -v #{name.shellescape}", out: '/dev/null') + return name + end + raise 'Cannot find chrome executable' + end + end + + def mktmpdir(&block) + Dir.mktmpdir('chrome-opal-', &block) + end + end + end +end diff --git a/lib/opal/cli_runners/chrome_cdp_interface.rb b/lib/opal/cli_runners/chrome_cdp_interface.rb new file mode 100644 index 00000000..be6f07cd --- /dev/null +++ b/lib/opal/cli_runners/chrome_cdp_interface.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +# This script I converted into Opal, so that I don't have to write +# buffer handling again. We have gets, Node has nothing close to it, +# even async. + +require 'opal/platform' + +%x{ +var CDP = require("chrome-remote-interface"); +var fs = require("fs"); + +var dir = #{ARGV.last} + +var options = { + host: #{ENV['CHROME_HOST'] || 'localhost'}, + port: #{ENV['CHROME_PORT'] || 9222} +}; + +CDP(options, function(client) { + var Page = client.Page, + Runtime = client.Runtime, + Console = client.Console; + + Promise.all([ + Console.enable(), + Page.enable(), + Runtime.enable(), + ]).then(function() { + // This hook catches only the first argument of `console.log` + // More advanced version Runtime.consoleAPICalled returns all arguments + // but all of them are not formatted, i.e. by calling + // console.log('string', [1, 2, 3], {a: 'b'}) + // it returns the following data to the callback: + // { + // "type":"log", + // "args":[ + // { + // "type":"string", + // "value":"string" + // }, + // { + // "type":"object", + // "subtype":"array", + // "className":"Array", + // "description":"Array(3)", + // "objectId":"{\"injectedScriptId\":11,\"id\":1}", + // "preview":{ + // "type":"object", + // "subtype":"array", + // "description":"Array(3)", + // "overflow":false, + // "properties":[ + // {"name":"0","type":"number","value":"1"}, + // {"name":"1","type":"number","value":"2"}, + // {"name":"2","type":"number","value":"3"} + // ] + // } + // }, + // { + // "type":"object", + // "className":"Object", + // "description":"Object", + // "objectId":"{\"injectedScriptId\":11,\"id\":2}", + // "preview":{ + // "type":"object", + // "description":"Object", + // "overflow":false, + // "properties":[ + // {"name":"a","type":"string","value":"b"} + // ] + // } + // } + // ], + // // ... + // } + // Supporting this format for complex data structure is challenging, feel free to contribute! + // + Console.messageAdded(function(console_message) { + process.stdout.write(console_message.message.text); + }); + + Runtime.exceptionThrown(function(exception) { + var properties = exception.exceptionDetails.exception.preview.properties, + stack, i; + + for (i = 0; i < properties.length; i++) { + var property = properties[i]; + + if (property.name == "stack") { + stack = property.value; + } + } + + console.log(stack); + + process.exit(1); + }); + + Page.javascriptDialogOpening((dialog) => { + #{ + if `dialog.type` == 'prompt' + message = gets&.chomp + if message + `Page.handleJavaScriptDialog({accept: true, promptText: #{message}})` + else + `Page.handleJavaScriptDialog({accept: false})` + end + end + } + }); + + Page.loadEventFired(() => { + Runtime.evaluate({ expression: "window.OPAL_EXIT_CODE" }).then(function(output) { + client.close(); + + if (typeof(output.result) !== "undefined" && output.result.type === "number") { + process.exit(output.result.value); + } else { + process.exit(0); + } + }) + }); + + Page.navigate({ url: "file://"+dir+"/index.html" }) + }); +}); +} diff --git a/lib/opal/cli_runners/compiler.rb b/lib/opal/cli_runners/compiler.rb new file mode 100644 index 00000000..4447ce6d --- /dev/null +++ b/lib/opal/cli_runners/compiler.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'opal/paths' + +# The compiler runner will just output the compiled JavaScript +Opal::CliRunners::Compiler = ->(data) { + options = data[:options] || {} + builder = data.fetch(:builder) + map_file = options[:map_file] + output = data.fetch(:output) + + compiled_source = builder.to_s + compiled_source += "\n" + builder.source_map.to_data_uri_comment unless options[:no_source_map] + output.puts compiled_source + File.write(map_file, builder.source_map.to_json) if map_file + + 0 +} diff --git a/lib/opal/cli_runners/gjs.rb b/lib/opal/cli_runners/gjs.rb new file mode 100644 index 00000000..d6ab6510 --- /dev/null +++ b/lib/opal/cli_runners/gjs.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'opal/paths' +require 'opal/cli_runners/system_runner' +require 'shellwords' + +module Opal + module CliRunners + # Gjs is GNOME's JavaScript runtime based on Mozilla SpiderMonkey + class Gjs + def self.call(data) + exe = ENV['GJS_PATH'] || 'gjs' + + opts = Shellwords.shellwords(ENV['GJS_OPTS'] || '') + + SystemRunner.call(data) do |tempfile| + [exe, *opts, tempfile.path, *data[:argv]] + end + rescue Errno::ENOENT + raise MissingGjs, 'Please install Gjs to be able to run Opal scripts.' + end + + class MissingGjs < RunnerError + end + end + end +end diff --git a/lib/opal/cli_runners/mini_racer.rb b/lib/opal/cli_runners/mini_racer.rb new file mode 100644 index 00000000..d9f9b80e --- /dev/null +++ b/lib/opal/cli_runners/mini_racer.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'mini_racer' +require 'opal/paths' + +module Opal + module CliRunners + class MiniRacer + def self.call(data) + ::MiniRacer::Platform.set_flags! :harmony + + builder = data.fetch(:builder) + output = data.fetch(:output) + # TODO: pass it + argv = data.fetch(:argv) + + v8 = ::MiniRacer::Context.new + v8.attach('prompt', ->(_msg = '') { $stdin.gets&.chomp }) + v8.attach('console.log', ->(i) { output.print(i); output.flush }) + v8.attach('console.warn', ->(i) { $stderr.print(i); $stderr.flush }) + v8.attach('crypto.randomBytes', method(:random_bytes).to_proc) + v8.attach('opalminiracer.exit', ->(status) { Kernel.exit(status) }) + v8.attach('opalminiracer.argv', argv) + + code = builder.to_s + "\n" + builder.source_map.to_data_uri_comment + + v8.eval(code) + end + + # A polyfill so that SecureRandom works in repl correctly. + def self.random_bytes(bytes) + ::SecureRandom.bytes(bytes).split('').map(&:ord) + end + end + end +end diff --git a/lib/opal/cli_runners/nashorn.rb b/lib/opal/cli_runners/nashorn.rb new file mode 100644 index 00000000..a6baecd1 --- /dev/null +++ b/lib/opal/cli_runners/nashorn.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'opal/paths' +require 'opal/cli_runners/system_runner' + +module Opal + module CliRunners + class Nashorn + def self.call(data) + # Allow to change path if using GraalVM, see: + # https://github.com/graalvm/graaljs/blob/master/docs/user/NashornMigrationGuide.md#launcher-name-js + exe = ENV['NASHORN_PATH'] || 'jjs' + + SystemRunner.call(data) do |tempfile| + [exe, tempfile.path, *data[:argv]] + end + rescue Errno::ENOENT + raise MissingNashorn, 'Please install JDK or GraalVM to be able to run Opal scripts.' + end + + class MissingNashorn < RunnerError + end + end + end +end diff --git a/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface b/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface new file mode 120000 index 00000000..b6257f3d --- /dev/null +++ b/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface @@ -0,0 +1 @@ +../chrome-remote-interface/bin/client.js \ No newline at end of file diff --git a/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE b/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE new file mode 100644 index 00000000..7e69daea --- /dev/null +++ b/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2017 Andrea Cardaci + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md b/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md new file mode 100644 index 00000000..399fb544 --- /dev/null +++ b/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md @@ -0,0 +1,843 @@ +chrome-remote-interface [![Build Status](https://travis-ci.org/cyrus-and/chrome-remote-interface.svg?branch=master)](https://travis-ci.org/cyrus-and/chrome-remote-interface) +======================= + +[Chrome Debugging Protocol] interface that helps to instrument Chrome (or any +other suitable [implementation](#implementations)) by providing a simple +abstraction of commands and notifications using a straightforward JavaScript +API. + +This module is one of the many [third-party protocol clients][3rd-party]. + +[3rd-party]: https://developer.chrome.com/devtools/docs/debugging-clients#chrome-remote-interface + +Sample API usage +---------------- + +The following snippet loads `https://github.com` and dumps every request made: + +```js +const CDP = require('chrome-remote-interface'); + +CDP((client) => { + // extract domains + const {Network, Page} = client; + // setup handlers + Network.requestWillBeSent((params) => { + console.log(params.request.url); + }); + Page.loadEventFired(() => { + client.close(); + }); + // enable events then start! + Promise.all([ + Network.enable(), + Page.enable() + ]).then(() => { + return Page.navigate({url: 'https://github.com'}); + }).catch((err) => { + console.error(err); + client.close(); + }); +}).on('error', (err) => { + // cannot connect to the remote endpoint + console.error(err); +}); +``` + +Find more examples in the [wiki], in particular notice how the above can be +rewritten using the [`async`/`await`][async-await-example] primitives. + +[wiki]: https://github.com/cyrus-and/chrome-remote-interface/wiki +[async-await-example]: https://github.com/cyrus-and/chrome-remote-interface/wiki/Async-await-example + +Installation +------------ + + npm install chrome-remote-interface + +Install globally (`-g`) to just use the [bundled client](#bundled-client). + +Implementations +--------------- + +This module should work with every application implementing the +[Chrome Debugging Protocol]. In particular, it has been tested against the +following implementations: + +Implementation | Protocol version | [Protocol] | [List] | [New] | [Activate] | [Close] | [Version] +---------------------------|--------------------|------------|--------|-------|------------|---------|----------- +[Google Chrome][1.1] | [tip-of-tree][1.2] | yes | yes | yes | yes | yes | yes +[Microsoft Edge][2.1] | [*partial*][2.2] | yes | yes | no | no | no | yes +[Node.js][3.1] ([v6.3.0]+) | [node][3.2] | yes | no | no | no | no | yes +[Safari (iOS)][4.1] | [*partial*][4.2] | no | yes | no | no | no | no + +[1.1]: #chromechromium +[1.2]: https://chromedevtools.github.io/devtools-protocol/tot/ + +[2.1]: #edge +[2.2]: https://github.com/Microsoft/edge-diagnostics-adapter/wiki/Supported-features-and-API + +[3.1]: #nodejs +[3.2]: https://chromedevtools.github.io/devtools-protocol/v8/ + +[4.1]: #safari-ios +[4.2]: http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/inspector/protocol + +[v6.3.0]: https://nodejs.org/en/blog/release/v6.3.0/ + +[Protocol]: #cdpprotocoloptions-callback +[List]: #cdplistoptions-callback +[New]: #cdpnewoptions-callback +[Activate]: #cdpactivateoptions-callback +[Close]: #cdpcloseoptions-callback +[Version]: #cdpversionoptions-callback + +The meaning of *target* varies according to the implementation, for example, +each Chrome tab represents a target whereas for Node.js a target is the +currently inspected script. + +Setup +----- + +An instance of either Chrome itself or another implementation needs to be +running on a known port in order to use this module (defaults to +`localhost:9222`). + +### Chrome/Chromium + +#### Desktop + +Start Chrome with the `--remote-debugging-port` option, for example: + + google-chrome --remote-debugging-port=9222 + +##### Headless + +Since version 59, additionally use the `--headless` option, for example: + + google-chrome --headless --remote-debugging-port=9222 + +#### Android + +Plug the device and enable the [port forwarding][adb], for example: + + adb forward tcp:9222 localabstract:chrome_devtools_remote + +[adb]: https://developer.chrome.com/devtools/docs/remote-debugging-legacy + +##### WebView + +In order to be inspectable, a WebView must +be [configured for debugging][webview] and the corresponding process ID must be +known. There are several ways to obtain it, for example: + + adb shell grep -a webview_devtools_remote /proc/net/unix + +Finally, port forwarding can be enabled as follows: + + adb forward tcp:9222 localabstract:webview_devtools_remote_ + +[webview]: https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews#configure_webviews_for_debugging + +### Edge + +Install and run the [Edge Diagnostics Adapter][edge-adapter]. + +[edge-adapter]: https://github.com/Microsoft/edge-diagnostics-adapter + +### Node.js + +Start Node.js with the `--inspect` option, for example: + + node --inspect=9222 script.js + +### Safari (iOS) + +Install and run the [iOS WebKit Debug Proxy][iwdp]. + +[iwdp]: https://github.com/google/ios-webkit-debug-proxy + +Bundled client +-------------- + +This module comes with a bundled client application that can be used to +interactively control a remote instance. + +### Target management + +The bundled client exposes subcommands to interact with the HTTP frontend +(e.g., [List](#cdplistoptions-callback), [New](#cdpnewoptions-callback), etc.), +run with `--help` to display the list of available options. + +Here are some examples: + +```javascript +$ chrome-remote-interface new 'http://example.com' +{ + "description": "", + "devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:9222/devtools/page/b049bb56-de7d-424c-a331-6ae44cf7ae01", + "id": "b049bb56-de7d-424c-a331-6ae44cf7ae01", + "thumbnailUrl": "/thumb/b049bb56-de7d-424c-a331-6ae44cf7ae01", + "title": "", + "type": "page", + "url": "http://example.com/", + "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/b049bb56-de7d-424c-a331-6ae44cf7ae01" +} +$ chrome-remote-interface close 'b049bb56-de7d-424c-a331-6ae44cf7ae01' +``` + +### Inspection + +Using the `inspect` subcommand it is possible to +perform [command execution](#clientdomainmethodparams-callback) +and [event binding](#clientdomaineventcallback) in a REPL fashion. But unlike +the regular API the callbacks are overridden to conveniently display the result +of the commands and the message of the events. Also, the event binding is +simplified here, executing a shorthand method (e.g., `Page.loadEventFired()`) +toggles the event registration. + +Remember that the REPL interface provides completion. + +Here is a sample session: + +```javascript +$ chrome-remote-interface inspect +>>> Runtime.evaluate({expression: 'window.location.toString()'}) +{ result: + { result: + { type: 'string', + value: 'https://www.google.it/_/chrome/newtab?espv=2&ie=UTF-8' }, + wasThrown: false } } +>>> Page.enable() +{ result: {} } +>>> Page.loadEventFired() // registered +{ 'Page.loadEventFired': true } +>>> Page.loadEventFired() // unregistered +{ 'Page.loadEventFired': false } +>>> Page.loadEventFired() // registered +{ 'Page.loadEventFired': true } +>>> Page.navigate({url: 'https://github.com'}) +{ result: { frameId: '28677.1' } } +{ 'Page.loadEventFired': { timestamp: 21385.383076 } } +>>> Runtime.evaluate({expression: 'window.location.toString()'}) +{ result: + { result: { type: 'string', value: 'https://github.com/' }, + wasThrown: false } } +``` + +#### Event filtering + +To reduce the amount of data displayed by the event listeners it is possible to +provide a filter function. In this example only the resource URL is shown: + +```javascript +$ chrome-remote-interface inspect +>>> Network.enable() +{ result: {} } +>>> Network.requestWillBeSent(params => params.request.url) +{ 'Network.requestWillBeSent': 'params => params.request.url' } +>>> Page.navigate({url: 'https://www.wikipedia.org'}) +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/' } +{ result: { frameId: '5530.1' } } +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia_wordmark.png' } +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2.png' } +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/portal/wikipedia.org/assets/js/index-3b68787aa6.js' } +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/portal/wikipedia.org/assets/js/gt-ie9-c84bf66d33.js' } +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/portal/wikipedia.org/assets/img/sprite-bookshelf_icons.png?16ed124e8ca7c5ce9d463e8f99b2064427366360' } +{ 'Network.requestWillBeSent': 'https://www.wikipedia.org/portal/wikipedia.org/assets/img/sprite-project-logos.png?9afc01c5efe0a8fb6512c776955e2ad3eb48fbca' } +``` + +Embedded documentation +---------------------- + +In both the REPL and the regular API every object of the protocol is *decorated* +with the meta information found within the descriptor. In addition The +`category` field is added, which determines if the member is a `command`, an +`event` or a `type`. + +For example to learn how to call `Page.navigate`: + +```javascript +>>> Page.navigate +{ [Function] + category: 'command', + parameters: { url: { type: 'string', description: 'URL to navigate the page to.' } }, + returns: + [ { name: 'frameId', + '$ref': 'FrameId', + hidden: true, + description: 'Frame id that will be navigated.' } ], + description: 'Navigates current page to the given URL.', + handlers: [ 'browser', 'renderer' ] } +``` + +To learn about the parameters returned by the `Network.requestWillBeSent` event: + +```javascript +>>> Network.requestWillBeSent +{ [Function] + category: 'event', + description: 'Fired when page is about to send HTTP request.', + parameters: + { requestId: { '$ref': 'RequestId', description: 'Request identifier.' }, + frameId: + { '$ref': 'Page.FrameId', + description: 'Frame identifier.', + hidden: true }, + loaderId: { '$ref': 'LoaderId', description: 'Loader identifier.' }, + documentURL: + { type: 'string', + description: 'URL of the document this request is loaded for.' }, + request: { '$ref': 'Request', description: 'Request data.' }, + timestamp: { '$ref': 'Timestamp', description: 'Timestamp.' }, + wallTime: + { '$ref': 'Timestamp', + hidden: true, + description: 'UTC Timestamp.' }, + initiator: { '$ref': 'Initiator', description: 'Request initiator.' }, + redirectResponse: + { optional: true, + '$ref': 'Response', + description: 'Redirect response data.' }, + type: + { '$ref': 'Page.ResourceType', + optional: true, + hidden: true, + description: 'Type of this resource.' } } } +``` + +To inspect the `Network.Request` (note that unlike commands and events, types +are named in upper camel case) type: + +```javascript +>>> Network.Request +{ category: 'type', + id: 'Request', + type: 'object', + description: 'HTTP request data.', + properties: + { url: { type: 'string', description: 'Request URL.' }, + method: { type: 'string', description: 'HTTP request method.' }, + headers: { '$ref': 'Headers', description: 'HTTP request headers.' }, + postData: + { type: 'string', + optional: true, + description: 'HTTP POST request data.' }, + mixedContentType: + { optional: true, + type: 'string', + enum: [Object], + description: 'The mixed content status of the request, as defined in http://www.w3.org/TR/mixed-content/' }, + initialPriority: + { '$ref': 'ResourcePriority', + description: 'Priority of the resource request at the time request is sent.' } } } +``` + +Chrome Debugging Protocol versions +---------------------------------- + +`chrome-remote-interface` uses the [local version] of the protocol descriptor by +default. This file is manually updated from time to time using +`scripts/update-protocol.sh` and pushed to this repository. + +This behavior can be changed by setting the `remote` option to `true` +upon [connection](#cdpoptions-callback), in which case the remote instance is +*asked* to provide its own protocol descriptor. + +Chrome < 60.0.3097.0 is not able to do that, so in that case the protocol +descriptor is fetched from the source repository. + +To override the above behavior there are basically three options: + +- pass a custom protocol descriptor upon [connection](#cdpoptions-callback) + (`protocol` option); + +- use the *raw* version of the [commands](#clientsendmethod-params-callback) + and [events](#event-domainmethod) interface; + +- update the local copy with `scripts/update-protocol.sh` (not present when + fetched with `npm install`). + +[local version]: lib/protocol.json + +Browser usage +------------- + +This module is able to run within a web context, with obvious limitations +though, namely external HTTP requests +([List](#cdplistoptions-callback), [New](#cdpnewoptions-callback), etc.) cannot +be performed directly, for this reason the user must provide a global +`criRequest` in order to use them: + +```js +function criRequest(options, callback) {} +``` + +`options` is the same object used by the Node.js `http` module and `callback` is +a function taking two arguments: `err` (JavaScript `Error` object or `null`) and +`data` (string result). + +### Using [webpack](https://webpack.github.io/) + +It just works, simply require this module: + +```js +const CDP = require('chrome-remote-interface'); +``` + +To use a non-minified version manually run webpack with: + + DEBUG=true npm run webpack + +### Using *vanilla* JavaScript + +To generate a JavaScript file that can be used with a ` + + ``` + +API +--- + +The API consists of three parts: + +- *DevTools* methods (for those [implementations](#implementations) that support + them, e.g., [List](#cdplistoptions-callback), [New](#cdpnewoptions-callback), + etc.); + +- [connection](#cdpoptions-callback) establishment; + +- the actual [protocol interaction](#class-cdp). + +### CDP([options], [callback]) + +Connects to a remote instance using the [Chrome Debugging Protocol]. + +`options` is an object with the following optional properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`; +- `target`: determines which target this client should attach to. The behavior + changes according to the type: + + - a `function` that takes the array returned by the `List` method and returns + a target or its numeric index relative to the array; + - a target `object` like those returned by the `New` and `List` methods; + - a `string` representing the raw WebSocket URL, in this case `host` and + `port` are not used to fetch the target list, yet they are used to complete + the URL if relative; + - a `string` representing the target id. + + Defaults to a function which returns the first available target according to + the implementation (note that at most one connection can be established to the + same target); +- `protocol`: [Chrome Debugging Protocol] descriptor object. Defaults to use the + protocol chosen according to the `remote` option; +- `remote`: a boolean indicating whether the protocol must be fetched *remotely* + or if the local version must be used. It has no effect if the `protocol` + option is set. Defaults to `false`. + +These options are also valid properties of all the instances of the `CDP` class. + +`callback` is a listener automatically added to the `connect` event of the +returned `EventEmitter`. When `callback` is omitted a `Promise` object is +returned which becomes fulfilled if the `connect` event is triggered and +rejected if the `error` event is triggered. + +The `EventEmitter` supports the following events: + +#### Event: 'connect' + +```javascript +function (client) {} +``` + +Emitted when the connection to the WebSocket is established. + +`client` is an instance of the `CDP` class. + +#### Event: 'error' + +```javascript +function (err) {} +``` + +Emitted when `http://host:port/json` cannot be reached or if it is not possible +to connect to the WebSocket. + +`err` is an instance of `Error`. + +### CDP.Protocol([options], [callback]) + +Fetch the [Chrome Debugging Protocol] descriptor. + +`options` is an object with the following optional properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`; +- `remote`: a boolean indicating whether the protocol must be fetched *remotely* + or if the local version must be returned. If it is not possible to fulfill the + request then the local version is used. Defaults to `false`. + +`callback` is executed when the protocol is fetched, it gets the following +arguments: + +- `err`: a `Error` object indicating the success status; +- `protocol`: an object with the following properties: + - `remote`: a boolean indicating whether the returned descriptor is the + remote version or not (due to user choice or error); + - `descriptor`: the [Chrome Debugging Protocol] descriptor. + +When `callback` is omitted a `Promise` object is returned. + +For example: + +```javascript +const CDP = require('chrome-remote-interface'); +CDP.Protocol(function (err, protocol) { + if (!err) { + console.log(JSON.stringify(protocol.descriptor, null, 4)); + } +}); +``` + +### CDP.List([options], [callback]) + +Request the list of the available open targets/tabs of the remote instance. + +`options` is an object with the following optional properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`. + +`callback` is executed when the list is correctly received, it gets the +following arguments: + +- `err`: a `Error` object indicating the success status; +- `targets`: the array returned by `http://host:port/json/list` containing the + target list. + +When `callback` is omitted a `Promise` object is returned. + +For example: + +```javascript +const CDP = require('chrome-remote-interface'); +CDP.List(function (err, targets) { + if (!err) { + console.log(targets); + } +}); +``` + +### CDP.New([options], [callback]) + +Create a new target/tab in the remote instance. + +`options` is an object with the following optional properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`; +- `url`: URL to load in the new target/tab. Defaults to `about:blank`. + +`callback` is executed when the target is created, it gets the following +arguments: + +- `err`: a `Error` object indicating the success status; +- `target`: the object returned by `http://host:port/json/new` containing the + target. + +When `callback` is omitted a `Promise` object is returned. + +For example: + +```javascript +const CDP = require('chrome-remote-interface'); +CDP.New(function (err, target) { + if (!err) { + console.log(target); + } +}); +``` + +### CDP.Activate([options], [callback]) + +Activate an open target/tab of the remote instance. + +`options` is an object with the following properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`; +- `id`: Target id. Required, no default. + +`callback` is executed when the response to the activation request is +received. It gets the following arguments: + +- `err`: a `Error` object indicating the success status; + +When `callback` is omitted a `Promise` object is returned. + +For example: + +```javascript +const CDP = require('chrome-remote-interface'); +CDP.Activate({'id': 'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'}, function (err) { + if (!err) { + console.log('target is activated'); + } +}); +``` + +### CDP.Close([options], [callback]) + +Close an open target/tab of the remote instance. + +`options` is an object with the following properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`; +- `id`: Target id. Required, no default. + +`callback` is executed when the response to the close request is received. It +gets the following arguments: + +- `err`: a `Error` object indicating the success status; + +When `callback` is omitted a `Promise` object is returned. + +For example: + +```javascript +const CDP = require('chrome-remote-interface'); +CDP.Close({'id': 'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'}, function (err) { + if (!err) { + console.log('target is closing'); + } +}); +``` + +Note that the callback is fired when the target is *queued* for removal, but the +actual removal will occur asynchronously. + +### CDP.Version([options], [callback]) + +Request version information from the remote instance. + +`options` is an object with the following optional properties: + +- `host`: HTTP frontend host. Defaults to `localhost`; +- `port`: HTTP frontend port. Defaults to `9222`; +- `secure`: HTTPS/WSS frontend. Defaults to `false`. + +`callback` is executed when the version information is correctly received, it +gets the following arguments: + +- `err`: a `Error` object indicating the success status; +- `info`: a JSON object returned by `http://host:port/json/version` containing + the version information. + +When `callback` is omitted a `Promise` object is returned. + +For example: + +```javascript +const CDP = require('chrome-remote-interface'); +CDP.Version(function (err, info) { + if (!err) { + console.log(info); + } +}); +``` + +### Class: CDP + +#### Event: 'event' + +```javascript +function (message) {} +``` + +Emitted when the remote instance sends any notification through the WebSocket. + +`message` is the object received, it has the following properties: + +- `method`: a string describing the notification (e.g., + `'Network.requestWillBeSent'`); +- `params`: an object containing the payload. + +Refer to the [Chrome Debugging Protocol] specification for more information. + +For example: + +```javascript +client.on('event', function (message) { + if (message.method === 'Network.requestWillBeSent') { + console.log(message.params); + } +}); +``` + +#### Event: '``.``' + +```javascript +function (params) {} +``` + +Emitted when the remote instance sends a notification for `.` +through the WebSocket. + +`params` is an object containing the payload. + +This is just a utility event which allows to easily listen for specific +notifications (see [`'event'`](#event-event)), for example: + +```javascript +client.on('Network.requestWillBeSent', console.log); +``` + +#### Event: 'ready' + +```javascript +function () {} +``` + +Emitted every time that there are no more pending commands waiting for a +response from the remote instance. The interaction is asynchronous so the only +way to serialize a sequence of commands is to use the callback provided by +the [`send`](#clientsendmethod-params-callback) method. This event acts as a +barrier and it is useful to avoid the *callback hell* in certain simple +situations. + +Users are encouraged to extensively check the response of each method and should +prefer the promises API when dealing with complex asynchronous program flows. + +For example to load a URL only after having enabled the notifications of both +`Network` and `Page` domains: + +```javascript +client.Network.enable(); +client.Page.enable(); +client.once('ready', function () { + client.Page.navigate({'url': 'https://github.com'}); +}); +``` + +In this particular case, not enforcing this kind of serialization may cause that +the remote instance does not properly deliver the desired notifications the +client. + + +#### Event: 'disconnect' + +```javascript +function () {} +``` + +Emitted when the instance closes the WebSocket connection. + +This may happen for example when the user opens DevTools or when the tab is +closed. + +#### client.send(method, [params], [callback]) + +Issue a command to the remote instance. + +`method` is a string describing the command. + +`params` is an object containing the payload. + +`callback` is executed when the remote instance sends a response to this +command, it gets the following arguments: + +- `error`: a boolean value indicating the success status, as reported by the + remote instance; +- `response`: an object containing either the response (`result` field, if + `error === false`) or the indication of the error (`error` field, if `error + === true`). + +When `callback` is omitted a `Promise` object is returned instead, with the +fulfilled/rejected states implemented according to the `error` parameter. + +Note that the field `id` mentioned in the [Chrome Debugging Protocol] +specification is managed internally and it is not exposed to the user. + +For example: + +```javascript +client.send('Page.navigate', {'url': 'https://github.com'}, console.log); +``` + +#### client.``.``([params], [callback]) + +Just a shorthand for: + +```javascript +client.send('.', params, callback); +``` + +For example: + +```javascript +client.Page.navigate({'url': 'https://github.com'}, console.log); +``` + +#### client.``.``([callback]) + +Just a shorthand for: + +```javascript +client.on('.', callback); +``` + +The only difference is that when `callback` is omitted the event is registered +only once and a `Promise` object is returned. + +For example: + +```javascript +client.Network.requestWillBeSent(console.log); +``` + +#### client.close([callback]) + +Close the connection to the remote instance. + +`callback` is executed when the WebSocket is successfully closed. + +When `callback` is omitted a `Promise` object is returned. + +Contributors +------------ + +- [Andrey Sidorov](https://github.com/sidorares) +- [Greg Cochard](https://github.com/gcochard) + +Resources +--------- + +- [Chrome Debugging Protocol] +- [Chrome Debugging Protocol Google group](https://groups.google.com/forum/#!forum/chrome-debugging-protocol) +- [devtools-protocol official repo](https://github.com/ChromeDevTools/devtools-protocol) +- [Showcase Chrome Debugging Protocol Clients](https://developer.chrome.com/devtools/docs/debugging-clients) +- [Awesome chrome-devtools](https://github.com/ChromeDevTools/awesome-chrome-devtools) + +[Chrome Debugging Protocol]: https://chromedevtools.github.io/devtools-protocol/ diff --git a/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js b/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js new file mode 100755 index 00000000..289e09eb --- /dev/null +++ b/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js @@ -0,0 +1,326 @@ +#!/usr/bin/env node + +'use strict'; + +const repl = require('repl'); +const util = require('util'); +const fs = require('fs'); +const path = require('path'); + +const program = require('commander'); + +const CDP = require('../'); + +function display(object) { + return util.inspect(object, { + 'colors': process.stdout.isTTY, + 'depth': null + }); +} + +function toJSON(object) { + return JSON.stringify(object, null, 4); +} + +function inheritProperties(from, to) { + Object.keys(from).forEach(function (property) { + to[property] = from[property]; + }); +} + +/// + +function inspect(target, args, options) { + options.remote = args.remote; + // otherwise the active target + if (target) { + if (args.webSocket) { + // by WebSocket URL + options.target = target; + } else { + // by target id + options.target = function (targets) { + return targets.findIndex(function (target) { + return target.id === target; + }); + }; + } + } + + if (args.protocol) { + options.protocol = JSON.parse(fs.readFileSync(args.protocol)); + } + + CDP(options, function (client) { + // keep track of registered events + const registeredEvents = {}; + + const cdpRepl = repl.start({ + 'prompt': '\x1b[32m>>>\x1b[0m ', + 'ignoreUndefined': true, + 'writer': display + }); + + const homePath = process.env.HOME || process.env.USERPROFILE; + const historyFile = path.join(homePath, '.cri_history'); + const historySize = 10000; + + function loadHistory() { + // attempt to open the history file + let fd; + try { + fd = fs.openSync(historyFile, 'r'); + } catch (err) { + return; // no history file present + } + // populate the REPL history + fs.readFileSync(fd, 'utf8') + .split('\n') + .filter(function (entry) { + return entry.trim(); + }) + .reverse() // to be compatible with repl.history files + .forEach(function (entry) { + cdpRepl.history.push(entry); + }); + } + + function saveHistory() { + // only store the last chunk + const entries = cdpRepl.history.slice(0, historySize).reverse().join('\n'); + fs.writeFileSync(historyFile, entries + '\n'); + } + + function overridePrompt(string) { + // hack to get rid of the prompt (clean line and reposition cursor) + console.log('\x1b[2K\x1b[G%s', string); + cdpRepl.displayPrompt(true); + } + + function overrideCommand(command) { + // hard code a callback to display the result + const override = function (params) { + command(params, function (error, response) { + const repr = {}; + repr[error ? 'error' : 'result'] = response; + overridePrompt(display(repr)); + }); + }; + // inherit the doc decorations + inheritProperties(command, override); + return override; + } + + function overrideEvent(client, domainName, itemName) { + const event = client[domainName][itemName]; + const eventName = domainName + '.' + itemName; + // hard code a callback to display the event data + const override = function (filter) { + // remove all the listeners (just one actually) anyway + client.removeAllListeners(eventName); + const status = {}; + // a filter will always enable/update the listener + if (!filter && registeredEvents[eventName]) { + delete registeredEvents[eventName]; + status[eventName] = false; + } else { + // use the filter (or true) as a status token + const statusToken = (filter ? filter.toString() : true); + status[eventName] = registeredEvents[eventName] = statusToken; + event(function (params) { + const repr = {}; + if (filter) { + params = filter(params); + } + repr[eventName] = params; + overridePrompt(display(repr)); + }); + } + // show the registration status to the user + return status; + }; + // inherit the doc decorations + inheritProperties(event, override); + return override; + } + + // enable history + loadHistory(); + + // disconnect on exit + cdpRepl.on('exit', function () { + console.log(); + client.close(); + saveHistory(); + }); + + // exit on disconnection + client.on('disconnect', function () { + console.error('Disconnected.'); + saveHistory(); + process.exit(1); + }); + + // add protocol API + client.protocol.domains.forEach(function (domainObject) { + // walk the domain names + const domainName = domainObject.domain; + cdpRepl.context[domainName] = {}; + Object.keys(client[domainName]).forEach(function (itemName) { + // walk the items in the domain and override commands and events + let item = client[domainName][itemName]; + switch (item.category) { + case 'command': + item = overrideCommand(item); + break; + case 'event': + item = overrideEvent(client, domainName, itemName); + break; + } + cdpRepl.context[domainName][itemName] = item; + }); + }); + }).on('error', function (err) { + console.error('Cannot connect to remote endpoint:', err.toString()); + }); +} + +function list(options) { + CDP.List(options, function (err, targets) { + if (err) { + console.error(err.toString()); + process.exit(1); + } + console.log(toJSON(targets)); + }); +} + +function _new(url, options) { + options.url = url; + CDP.New(options, function (err, target) { + if (err) { + console.error(err.toString()); + process.exit(1); + } + console.log(toJSON(target)); + }); +} + +function activate(args, options) { + options.id = args; + CDP.Activate(options, function (err) { + if (err) { + console.error(err.toString()); + process.exit(1); + } + }); +} + +function close(args, options) { + options.id = args; + CDP.Close(options, function (err) { + if (err) { + console.error(err.toString()); + process.exit(1); + } + }); +} + +function version(options) { + CDP.Version(options, function (err, info) { + if (err) { + console.error(err.toString()); + process.exit(1); + } + console.log(toJSON(info)); + }); +} + +function protocol(args, options) { + options.remote = args.remote; + CDP.Protocol(options, function (err, protocol) { + if (err) { + console.error(err.toString()); + process.exit(1); + } + console.log(toJSON(protocol)); + }); +} + +/// + +let action; + +program + .option('-t, --host ', 'HTTP frontend host') + .option('-p, --port ', 'HTTP frontend port') + .option('-s, --secure', 'HTTPS/WSS frontend'); + +program + .command('inspect []') + .description('inspect a target (defaults to the first available target)') + .option('-w, --web-socket', 'interpret as a WebSocket URL instead of a target id') + .option('-j, --protocol ', 'Chrome Debugging Protocol descriptor (overrides `--remote`)') + .option('-r, --remote', 'Attempt to fetch the protocol descriptor remotely') + .action(function (target, args) { + action = inspect.bind(null, target, args); + }); + +program + .command('list') + .description('list all the available targets/tabs') + .action(function () { + action = list; + }); + +program + .command('new []') + .description('create a new target/tab') + .action(function (url) { + action = _new.bind(null, url); + }); + +program + .command('activate ') + .description('activate a target/tab by id') + .action(function (id) { + action = activate.bind(null, id); + }); + +program + .command('close ') + .description('close a target/tab by id') + .action(function (id) { + action = close.bind(null, id); + }); + +program + .command('version') + .description('show the browser version') + .action(function () { + action = version; + }); + +program + .command('protocol') + .description('show the currently available protocol descriptor') + .option('-r, --remote', 'Attempt to fetch the protocol descriptor remotely') + .action(function (args) { + action = protocol.bind(null, args); + }); + +program.parse(process.argv); + +// common options +const options = { + 'host': program.host, + 'port': program.port, + 'secure': program.secure +}; + +if (action) { + action(options); +} else { + program.outputHelp(); + process.exit(1); +} diff --git a/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js b/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js new file mode 100644 index 00000000..621cb294 --- /dev/null +++ b/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js @@ -0,0 +1,11 @@ +module.exports=function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){(function(t){"use strict";var r=n(2),i=n(3),o=n(43);e.exports=function(e,n){"function"==typeof e&&(n=e,e=void 0);var i=new r;return"function"==typeof n?(t.nextTick(function(){new o(e,i)}),i.once("connect",n)):new Promise(function(t,n){i.once("connect",t),i.once("error",n),new o(e,i)})},e.exports.listTabs=i.List,e.exports.spawnTab=i.New,e.exports.closeTab=i.Close,e.exports.Protocol=i.Protocol,e.exports.List=i.List,e.exports.New=i.New,e.exports.Activate=i.Activate,e.exports.Close=i.Close,e.exports.Version=i.Version}).call(t,n(1))},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(d===setTimeout)return setTimeout(e,0);if((d===n||!d)&&setTimeout)return d=setTimeout,setTimeout(e,0);try{return d(e,0)}catch(t){try{return d.call(null,e,0)}catch(t){return d.call(this,e,0)}}}function o(e){if(l===clearTimeout)return clearTimeout(e);if((l===r||!l)&&clearTimeout)return l=clearTimeout,clearTimeout(e);try{return l(e)}catch(t){try{return l.call(null,e)}catch(t){return l.call(this,e)}}}function a(){f&&u&&(f=!1,u.length?h=u.concat(h):y=-1,h.length&&s())}function s(){if(!f){var e=i(a);f=!0;for(var t=h.length;t;){for(u=h,h=[];++y1)for(var n=1;n0&&this._events[e].length>i&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function n(){this.removeListener(e,n),i||(i=!0,t.apply(this,arguments))}if(!r(t))throw TypeError("listener must be a function");var i=!1;return n.listener=t,this.on(e,n),this},n.prototype.removeListener=function(e,t){var n,i,a,s;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],a=n.length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(s=a;s-- >0;)if(n[s]===t||n[s].listener&&n[s].listener===t){i=s;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],r(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){(function(t){"use strict";function r(e,t){e.host=e.host||d.HOST,e.port=e.port||d.PORT,e.secure=!!e.secure,l(e.secure?c:p,e,t)}function i(e){return function(t,n){return"function"==typeof t&&(n=t,t=void 0),t=t||{},"function"!=typeof n?new Promise(function(n,r){e(t,function(e,t){e?r(e):n(t)})}):void e(t,n)}}function o(e){return e.split(".").map(function(e){return parseInt(e)})}function a(e,n,r){var i=n["WebKit-Version"],a=n["V8-Version"],s=i.match(/\s\(@(\b[0-9a-f]{5,40}\b)/),p=s[1],d=p<=202666,m=void 0;if(d)m=["https://src.chromium.org/blink/trunk/Source/devtools/protocol.json?p="+p];else{var u="53.0.2758.1",h="55.0.2854.3",f=o(n.Browser.split("/")[1]),y=f[2]<=o(u)[2],g=f[2]<=o(h)[2];y?m=["https://chromium.googlesource.com/chromium/src/+/"+p+"/third_party/WebKit/Source/devtools/protocol.json?format=TEXT"]:g?m=["https://chromium.googlesource.com/chromium/src/+/"+p+"/third_party/WebKit/Source/core/inspector/browser_protocol.json?format=TEXT","https://chromium.googlesource.com/chromium/src/+/"+p+"/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json?format=TEXT"]:a?m=["https://chromium.googlesource.com/chromium/src/+/"+p+"/third_party/WebKit/Source/core/inspector/browser_protocol.json?format=TEXT","https://chromium.googlesource.com/v8/v8/+/"+a+"/src/inspector/js_protocol.json?format=TEXT"]:(console.error("Warning: the protocol might be outdated, see: https://groups.google.com/d/topic/chrome-debugging-protocol/HjyOKainKus/discussion"),m=["https://chromium.googlesource.com/chromium/src/+/"+p+"/third_party/WebKit/Source/core/inspector/browser_protocol.json?format=TEXT","https://chromium.googlesource.com/chromium/src/+/"+h+"/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json?format=TEXT"])}var b=[];m.forEach(function(e){l(c,e,function(e,n){var i=void 0;if(!e)try{d||(n=new t(n,"base64").toString()),i=JSON.parse(n)}catch(e){}if(b.push(i),b.length===m.length){if(b.indexOf(void 0)!==-1)return void r(new Error("Cannot fetch from Chromium repo"));b.forEach(function(e,t){0!==t&&Array.prototype.push.apply(b[0].domains,e.domains)}),r(null,b[0])}})})}function s(e,t,n){e.path="/json/protocol",r(e,function(e,t){e?n(e):n(null,JSON.parse(t))})}var p=n(8),c=n(39),d=n(40),l=n(41);e.exports.Protocol=i(function(t,r){if(!t.remote){var i=n(42);return void r(null,{remote:!1,descriptor:i})}e.exports.Version(t,function(e,n){if(e)return void r(e);var i=(n[0]||n).Browser,p=void 0;if(i.match(/^(Headless)?Chrome\//)){var c="60.0.3097.0",d=o(c)[2],l=o(n.Browser.split("/")[1])[2];p=l=i())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i().toString(16)+" bytes");return 0|e}function y(e){return+e!=e&&(e=0),a.alloc(+e)}function g(e,t){if(a.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return z(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return G(e).length;default:if(r)return z(e).length;t=(""+t).toLowerCase(),r=!0}}function b(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return A(this,t,n);case"utf8":case"utf-8":return O(this,t,n);case"ascii":return D(this,t,n);case"latin1":case"binary":return j(this,t,n);case"base64":return $(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return P(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function w(e,t,n,r,i){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"==typeof t&&(t=a.from(t,r)),a.isBuffer(t))return 0===t.length?-1:S(e,t,n,r,i);if("number"==typeof t)return t&=255,a.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):S(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function S(e,t,n,r,i){function o(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}var a=1,s=e.length,p=t.length;if(void 0!==r&&(r=String(r).toLowerCase(),"ucs2"===r||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,p/=2,n/=2}var c;if(i){var d=-1;for(c=n;cs&&(n=s-p),c=n;c>=0;c--){for(var l=!0,m=0;mi&&(r=i)):r=i;var o=t.length;if(o%2!==0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var a=0;a239?4:o>223?3:o>191?2:1;if(i+s<=n){var p,c,d,l;switch(s){case 1:o<128&&(a=o);break;case 2:p=e[i+1],128===(192&p)&&(l=(31&o)<<6|63&p,l>127&&(a=l));break;case 3:p=e[i+1],c=e[i+2],128===(192&p)&&128===(192&c)&&(l=(15&o)<<12|(63&p)<<6|63&c,l>2047&&(l<55296||l>57343)&&(a=l));break;case 4:p=e[i+1],c=e[i+2],d=e[i+3],128===(192&p)&&128===(192&c)&&128===(192&d)&&(l=(15&o)<<18|(63&p)<<12|(63&c)<<6|63&d,l>65535&&l<1114112&&(a=l))}}null===a?(a=65533,s=1):a>65535&&(a-=65536,r.push(a>>>10&1023|55296),a=56320|1023&a),r.push(a),i+=s}return E(r)}function E(e){var t=e.length;if(t<=ee)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function M(e,t,n,r,i,o){if(!a.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function L(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function _(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function q(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function U(e,t,n,r,i){return i||q(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),Q.write(e,t,n,r,23,4),n+4}function F(e,t,n,r,i){return i||q(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),Q.write(e,t,n,r,52,8),n+8}function B(e){if(e=W(e).replace(te,""),e.length<2)return"";for(;e.length%4!==0;)e+="=";return e}function W(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function H(e){return e<16?"0"+e.toString(16):e.toString(16)}function z(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],a=0;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=(i-55296<<10|n-56320)+65536}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function V(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function G(e){return K.toByteArray(B(e))}function Y(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function J(e){return e!==e}var K=n(5),Q=n(6),Z=n(7);t.Buffer=a,t.SlowBuffer=y,t.INSPECT_MAX_BYTES=50,a.TYPED_ARRAY_SUPPORT=void 0!==e.TYPED_ARRAY_SUPPORT?e.TYPED_ARRAY_SUPPORT:r(),t.kMaxLength=i(),a.poolSize=8192,a._augment=function(e){return e.__proto__=a.prototype,e},a.from=function(e,t,n){return s(null,e,t,n)},a.TYPED_ARRAY_SUPPORT&&(a.prototype.__proto__=Uint8Array.prototype,a.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&a[Symbol.species]===a&&Object.defineProperty(a,Symbol.species,{value:null,configurable:!0})),a.alloc=function(e,t,n){return c(null,e,t,n)},a.allocUnsafe=function(e){return d(null,e)},a.allocUnsafeSlow=function(e){return d(null,e)},a.isBuffer=function(e){return!(null==e||!e._isBuffer)},a.compare=function(e,t){if(!a.isBuffer(e)||!a.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,i=0,o=Math.min(n,r);i0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},a.prototype.compare=function(e,t,n,r,i){if(!a.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var o=i-r,s=n-t,p=Math.min(o,s),c=this.slice(r,i),d=e.slice(t,n),l=0;li)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return x(this,e,t,n);case"utf8":case"utf-8":return I(this,e,t,n);case"ascii":return T(this,e,t,n);case"latin1":case"binary":return R(this,e,t,n);case"base64":return k(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return C(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},a.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var ee=4096;a.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n,e<0&&(e=0)):e>n&&(e=n),t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},a.prototype.readUInt8=function(e,t){return t||N(e,1,this.length),this[e]},a.prototype.readUInt16LE=function(e,t){return t||N(e,2,this.length),this[e]|this[e+1]<<8},a.prototype.readUInt16BE=function(e,t){return t||N(e,2,this.length),this[e]<<8|this[e+1]},a.prototype.readUInt32LE=function(e,t){return t||N(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},a.prototype.readUInt32BE=function(e,t){return t||N(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},a.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||N(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},a.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||N(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},a.prototype.readInt8=function(e,t){return t||N(e,1,this.length),128&this[e]?(255-this[e]+1)*-1:this[e]},a.prototype.readInt16LE=function(e,t){t||N(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},a.prototype.readInt16BE=function(e,t){t||N(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},a.prototype.readInt32LE=function(e,t){return t||N(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},a.prototype.readInt32BE=function(e,t){return t||N(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},a.prototype.readFloatLE=function(e,t){return t||N(e,4,this.length),Q.read(this,e,!0,23,4)},a.prototype.readFloatBE=function(e,t){return t||N(e,4,this.length),Q.read(this,e,!1,23,4)},a.prototype.readDoubleLE=function(e,t){return t||N(e,8,this.length),Q.read(this,e,!0,52,8)},a.prototype.readDoubleBE=function(e,t){return t||N(e,8,this.length),Q.read(this,e,!1,52,8)},a.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t|=0,n|=0,!r){var i=Math.pow(2,8*n)-1;M(this,e,t,n,i,0)}var o=1,a=0;for(this[t]=255&e;++a=0&&(a*=256);)this[t+o]=e/a&255;return t+n},a.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,1,255,0),a.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},a.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,65535,0),a.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},a.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,65535,0),a.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},a.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,4294967295,0),a.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):_(this,e,t,!0),t+4},a.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,4294967295,0),a.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):_(this,e,t,!1),t+4},a.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);M(this,e,t,n,i-1,-i)}var o=0,a=1,s=0;for(this[t]=255&e;++o>0)-s&255;return t+n},a.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);M(this,e,t,n,i-1,-i)}var o=n-1,a=1,s=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===s&&0!==this[t+o+1]&&(s=1),this[t+o]=(e/a>>0)-s&255;return t+n},a.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,1,127,-128),a.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},a.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,32767,-32768),a.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},a.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,32767,-32768),a.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},a.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,2147483647,-2147483648),a.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):_(this,e,t,!0),t+4},a.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),a.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):_(this,e,t,!1),t+4},a.prototype.writeFloatLE=function(e,t,n){return U(this,e,t,!0,n)},a.prototype.writeFloatBE=function(e,t,n){return U(this,e,t,!1,n)},a.prototype.writeDoubleLE=function(e,t,n){return F(this,e,t,!0,n)},a.prototype.writeDoubleBE=function(e,t,n){return F(this,e,t,!1,n)},a.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--i)e[i+t]=this[i+n];else if(o<1e3||!a.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,n=void 0===n?this.length:n>>>0,e||(e=0);var o;if("number"==typeof e)for(o=t;o0)throw new Error("Invalid string. Length must be a multiple of 4");return"="===e[t-2]?2:"="===e[t-1]?1:0}function r(e){return 3*e.length/4-n(e)}function i(e){var t,r,i,o,a,s,p=e.length;a=n(e),s=new d(3*p/4-a),i=a>0?p-4:p;var l=0;for(t=0,r=0;t>16&255,s[l++]=o>>8&255,s[l++]=255&o;return 2===a?(o=c[e.charCodeAt(t)]<<2|c[e.charCodeAt(t+1)]>>4,s[l++]=255&o):1===a&&(o=c[e.charCodeAt(t)]<<10|c[e.charCodeAt(t+1)]<<4|c[e.charCodeAt(t+2)]>>2,s[l++]=o>>8&255,s[l++]=255&o),s}function o(e){return p[e>>18&63]+p[e>>12&63]+p[e>>6&63]+p[63&e]}function a(e,t,n){for(var r,i=[],a=t;ad?d:c+s));return 1===r?(t=e[n-1],i+=p[t>>2],i+=p[t<<4&63],i+="=="):2===r&&(t=(e[n-2]<<8)+e[n-1],i+=p[t>>10],i+=p[t>>4&63],i+=p[t<<2&63],i+="="),o.push(i),o.join("")}t.byteLength=r,t.toByteArray=i,t.fromByteArray=s;for(var p=[],c=[],d="undefined"!=typeof Uint8Array?Uint8Array:Array,l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",m=0,u=l.length;m>1,d=-7,l=n?i-1:0,m=n?-1:1,u=e[t+l];for(l+=m,o=u&(1<<-d)-1,u>>=-d,d+=s;d>0;o=256*o+e[t+l],l+=m,d-=8);for(a=o&(1<<-d)-1,o>>=-d,d+=r;d>0;a=256*a+e[t+l],l+=m,d-=8);if(0===o)o=1-c;else{if(o===p)return a?NaN:(u?-1:1)*(1/0);a+=Math.pow(2,r),o-=c}return(u?-1:1)*a*Math.pow(2,o-r)},t.write=function(e,t,n,r,i,o){var a,s,p,c=8*o-i-1,d=(1<>1,m=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,u=r?0:o-1,h=r?1:-1,f=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=d):(a=Math.floor(Math.log(t)/Math.LN2),t*(p=Math.pow(2,-a))<1&&(a--,p*=2),t+=a+l>=1?m/p:m*Math.pow(2,1-l),t*p>=2&&(a++,p/=2),a+l>=d?(s=0,a=d):a+l>=1?(s=(t*p-1)*Math.pow(2,i),a+=l):(s=t*Math.pow(2,l-1)*Math.pow(2,i),a=0));i>=8;e[n+u]=255&s,u+=h,s/=256,i-=8);for(a=a<0;e[n+u]=255&a,u+=h,a/=256,c-=8);e[n+u-h]|=128*f}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){(function(e){var r=n(9),i=n(30),o=n(31),a=n(32),s=t;s.request=function(t,n){t="string"==typeof t?a.parse(t):i(t);var o=e.location.protocol.search(/^https?:$/)===-1?"http:":"",s=t.protocol||o,p=t.hostname||t.host,c=t.port,d=t.path||"/";p&&p.indexOf(":")!==-1&&(p="["+p+"]"),t.url=(p?s+"//"+p:"")+(c?":"+c:"")+d,t.method=(t.method||"GET").toUpperCase(), +t.headers=t.headers||{};var l=new r(t);return n&&l.on("response",n),l},s.get=function(e,t){var n=s.request(e,t);return n.end(),n},s.Agent=function(){},s.Agent.defaultMaxSockets=4,s.STATUS_CODES=o,s.METHODS=["CHECKOUT","CONNECT","COPY","DELETE","GET","HEAD","LOCK","M-SEARCH","MERGE","MKACTIVITY","MKCOL","MOVE","NOTIFY","OPTIONS","PATCH","POST","PROPFIND","PROPPATCH","PURGE","PUT","REPORT","SEARCH","SUBSCRIBE","TRACE","UNLOCK","UNSUBSCRIBE"]}).call(t,function(){return this}())},function(e,t,n){(function(t,r,i){function o(e,t){return s.fetch&&t?"fetch":s.mozchunkedarraybuffer?"moz-chunked-arraybuffer":s.msstream?"ms-stream":s.arraybuffer&&e?"arraybuffer":s.vbArray&&e?"text:vbarray":"text"}function a(e){try{var t=e.status;return null!==t&&0!==t}catch(e){return!1}}var s=n(10),p=n(11),c=n(12),d=n(13),l=n(29),m=c.IncomingMessage,u=c.readyStates,h=e.exports=function(e){var n=this;d.Writable.call(n),n._opts=e,n._body=[],n._headers={},e.auth&&n.setHeader("Authorization","Basic "+new t(e.auth).toString("base64")),Object.keys(e.headers).forEach(function(t){n.setHeader(t,e.headers[t])});var r,i=!0;if("disable-fetch"===e.mode||"timeout"in e)i=!1,r=!0;else if("prefer-streaming"===e.mode)r=!1;else if("allow-wrong-content-type"===e.mode)r=!s.overrideMimeType;else{if(e.mode&&"default"!==e.mode&&"prefer-fast"!==e.mode)throw new Error("Invalid value for opts.mode");r=!0}n._mode=o(r,i),n.on("finish",function(){n._onFinish()})};p(h,d.Writable),h.prototype.setHeader=function(e,t){var n=this,r=e.toLowerCase();f.indexOf(r)===-1&&(n._headers[r]={name:e,value:t})},h.prototype.getHeader=function(e){var t=this._headers[e.toLowerCase()];return t?t.value:null},h.prototype.removeHeader=function(e){var t=this;delete t._headers[e.toLowerCase()]},h.prototype._onFinish=function(){var e=this;if(!e._destroyed){var n=e._opts,o=e._headers,a=null;"GET"!==n.method&&"HEAD"!==n.method&&(a=s.blobConstructor?new r.Blob(e._body.map(function(e){return l(e)}),{type:(o["content-type"]||{}).value||""}):t.concat(e._body).toString());var p=[];if(Object.keys(o).forEach(function(e){var t=o[e].name,n=o[e].value;Array.isArray(n)?n.forEach(function(e){p.push([t,e])}):p.push([t,n])}),"fetch"===e._mode)r.fetch(e._opts.url,{method:e._opts.method,headers:p,body:a||void 0,mode:"cors",credentials:n.withCredentials?"include":"same-origin"}).then(function(t){e._fetchResponse=t,e._connect()},function(t){e.emit("error",t)});else{var c=e._xhr=new r.XMLHttpRequest;try{c.open(e._opts.method,e._opts.url,!0)}catch(t){return void i.nextTick(function(){e.emit("error",t)})}"responseType"in c&&(c.responseType=e._mode.split(":")[0]),"withCredentials"in c&&(c.withCredentials=!!n.withCredentials),"text"===e._mode&&"overrideMimeType"in c&&c.overrideMimeType("text/plain; charset=x-user-defined"),"timeout"in n&&(c.timeout=n.timeout,c.ontimeout=function(){e.emit("timeout")}),p.forEach(function(e){c.setRequestHeader(e[0],e[1])}),e._response=null,c.onreadystatechange=function(){switch(c.readyState){case u.LOADING:case u.DONE:e._onXHRProgress()}},"moz-chunked-arraybuffer"===e._mode&&(c.onprogress=function(){e._onXHRProgress()}),c.onerror=function(){e._destroyed||e.emit("error",new Error("XHR error"))};try{c.send(a)}catch(t){return void i.nextTick(function(){e.emit("error",t)})}}}},h.prototype._onXHRProgress=function(){var e=this;a(e._xhr)&&!e._destroyed&&(e._response||e._connect(),e._response._onXHRProgress())},h.prototype._connect=function(){var e=this;e._destroyed||(e._response=new m(e._xhr,e._fetchResponse,e._mode),e._response.on("error",function(t){e.emit("error",t)}),e.emit("response",e._response))},h.prototype._write=function(e,t,n){var r=this;r._body.push(e),n()},h.prototype.abort=h.prototype.destroy=function(){var e=this;e._destroyed=!0,e._response&&(e._response._destroyed=!0),e._xhr&&e._xhr.abort()},h.prototype.end=function(e,t,n){var r=this;"function"==typeof e&&(n=e,e=void 0),d.Writable.prototype.end.call(r,e,t,n)},h.prototype.flushHeaders=function(){},h.prototype.setTimeout=function(){},h.prototype.setNoDelay=function(){},h.prototype.setSocketKeepAlive=function(){};var f=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","date","dnt","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","user-agent","via"]}).call(t,n(4).Buffer,function(){return this}(),n(1))},function(e,t){(function(e){function n(){if(void 0!==o)return o;if(e.XMLHttpRequest){o=new e.XMLHttpRequest;try{o.open("GET",e.XDomainRequest?"/":"https://example.com")}catch(e){o=null}}else o=null;return o}function r(e){var t=n();if(!t)return!1;try{return t.responseType=e,t.responseType===e}catch(e){}return!1}function i(e){return"function"==typeof e}t.fetch=i(e.fetch)&&i(e.ReadableStream),t.blobConstructor=!1;try{new Blob([new ArrayBuffer(1)]),t.blobConstructor=!0}catch(e){}var o,a="undefined"!=typeof e.ArrayBuffer,s=a&&i(e.ArrayBuffer.prototype.slice);t.arraybuffer=t.fetch||a&&r("arraybuffer"),t.msstream=!t.fetch&&s&&r("ms-stream"),t.mozchunkedarraybuffer=!t.fetch&&a&&r("moz-chunked-arraybuffer"),t.overrideMimeType=t.fetch||!!n()&&i(n().overrideMimeType),t.vbArray=i(e.VBArray),o=null}).call(t,function(){return this}())},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){(function(e,r,i){var o=n(10),a=n(11),s=n(13),p=t.readyStates={UNSENT:0,OPENED:1,HEADERS_RECEIVED:2,LOADING:3,DONE:4},c=t.IncomingMessage=function(t,n,i){function a(){c.read().then(function(e){if(!p._destroyed){if(e.done)return void p.push(null);p.push(new r(e.value)),a()}}).catch(function(e){p.emit("error",e)})}var p=this;if(s.Readable.call(p),p._mode=i,p.headers={},p.rawHeaders=[],p.trailers={},p.rawTrailers=[],p.on("end",function(){e.nextTick(function(){p.emit("close")})}),"fetch"===i){p._fetchResponse=n,p.url=n.url,p.statusCode=n.status,p.statusMessage=n.statusText,n.headers.forEach(function(e,t){p.headers[t.toLowerCase()]=e,p.rawHeaders.push(t,e)});var c=n.body.getReader();a()}else{p._xhr=t,p._pos=0,p.url=t.responseURL,p.statusCode=t.status,p.statusMessage=t.statusText;var d=t.getAllResponseHeaders().split(/\r?\n/);if(d.forEach(function(e){var t=e.match(/^([^:]+):\s*(.*)/);if(t){var n=t[1].toLowerCase();"set-cookie"===n?(void 0===p.headers[n]&&(p.headers[n]=[]),p.headers[n].push(t[2])):void 0!==p.headers[n]?p.headers[n]+=", "+t[2]:p.headers[n]=t[2],p.rawHeaders.push(t[1],t[2])}}),p._charset="x-user-defined",!o.overrideMimeType){var l=p.rawHeaders["mime-type"];if(l){var m=l.match(/;\s*charset=([^;])(;|$)/);m&&(p._charset=m[1].toLowerCase())}p._charset||(p._charset="utf-8")}}};a(c,s.Readable),c.prototype._read=function(){},c.prototype._onXHRProgress=function(){var e=this,t=e._xhr,n=null;switch(e._mode){case"text:vbarray":if(t.readyState!==p.DONE)break;try{n=new i.VBArray(t.responseBody).toArray()}catch(e){}if(null!==n){e.push(new r(n));break}case"text":try{n=t.responseText}catch(t){e._mode="text:vbarray";break}if(n.length>e._pos){var o=n.substr(e._pos);if("x-user-defined"===e._charset){for(var a=new r(o.length),s=0;se._pos&&(e.push(new r(new Uint8Array(c.result.slice(e._pos)))),e._pos=c.result.byteLength)},c.onload=function(){e.push(null)},c.readAsArrayBuffer(n)}e._xhr.readyState===p.DONE&&"ms-stream"!==e._mode&&e.push(null)}}).call(t,n(1),n(4).Buffer,function(){return this}())},function(e,t,n){t=e.exports=n(14),t.Stream=t,t.Readable=t,t.Writable=n(22),t.Duplex=n(21),t.Transform=n(27),t.PassThrough=n(28)},function(e,t,n){(function(t){"use strict";function r(e,t,n){return"function"==typeof e.prependListener?e.prependListener(t,n):void(e._events&&e._events[t]?E(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n))}function i(e,t){$=$||n(21),e=e||{},this.objectMode=!!e.objectMode,t instanceof $&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var r=e.highWaterMark,i=this.objectMode?16:16384;this.highWaterMark=r||0===r?r:i,this.highWaterMark=~~this.highWaterMark,this.buffer=new _,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.ranOut=!1,this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(L||(L=n(26).StringDecoder),this.decoder=new L(e.encoding),this.encoding=e.encoding)}function o(e){return $=$||n(21),this instanceof o?(this._readableState=new i(e,this),this.readable=!0,e&&"function"==typeof e.read&&(this._read=e.read),void j.call(this)):new o(e)}function a(e,t,n,r,i){var o=d(t,n);if(o)e.emit("error",o);else if(null===n)t.reading=!1,l(e,t);else if(t.objectMode||n&&n.length>0)if(t.ended&&!i){var a=new Error("stream.push() after EOF");e.emit("error",a)}else if(t.endEmitted&&i){var p=new Error("stream.unshift() after end event");e.emit("error",p)}else{var c;!t.decoder||i||r||(n=t.decoder.write(n),c=!t.objectMode&&0===n.length),i||(t.reading=!1),c||(t.flowing&&0===t.length&&!t.sync?(e.emit("data",n),e.read(0)):(t.length+=t.objectMode?1:n.length,i?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&m(e))),h(e,t)}else i||(t.reading=!1);return s(t)}function s(e){return!e.ended&&(e.needReadable||e.length=U?e=U:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function c(e,t){return e<=0||0===t.length&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=p(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function d(e,t){var n=null;return A.isBuffer(t)||"string"==typeof t||null===t||void 0===t||e.objectMode||(n=new TypeError("Invalid non-string/buffer chunk")),n}function l(e,t){if(!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,m(e)}}function m(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(M("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?O(u,e):u(e))}function u(e){M("emit readable"),e.emit("readable"),w(e)}function h(e,t){t.readingMore||(t.readingMore=!0,O(f,e,t))}function f(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=x(e,t.buffer,t.decoder),n}function x(e,t,n){var r;return eo.length?o.length:e;if(i+=a===o.length?o:o.slice(0,e),e-=a,0===e){a===o.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=o.slice(a));break}++r}return t.length-=r,i}function T(e,t){var n=A.allocUnsafe(e),r=t.head,i=1;for(r.data.copy(n),e-=r.data.length;r=r.next;){var o=r.data,a=e>o.length?o.length:e;if(o.copy(n,n.length-e,0,a),e-=a,0===e){a===o.length?(++i,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=o.slice(a));break}++i}return t.length-=i,n}function R(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,O(k,t,e))}function k(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function C(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return M("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?R(this):m(this),null;if(e=c(e,t),0===e&&t.ended)return 0===t.length&&R(this),null;var r=t.needReadable;M("need readable",r),(0===t.length||t.length-e0?S(e,t):null,null===i?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&R(this)),null!==i&&this.emit("data",i),i},o.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},o.prototype.pipe=function(e,n){function i(e){M("onunpipe"),e===m&&a()}function o(){M("onend"),e.end()}function a(){M("cleanup"),e.removeListener("close",c),e.removeListener("finish",d),e.removeListener("drain",g),e.removeListener("error",p),e.removeListener("unpipe",i),m.removeListener("end",o),m.removeListener("end",l),m.removeListener("data",s),b=!0,!u.awaitDrain||e._writableState&&!e._writableState.needDrain||g()}function s(t){M("ondata"),v=!1;var n=e.write(t);!1!==n||v||((1===u.pipesCount&&u.pipes===e||u.pipesCount>1&&C(u.pipes,e)!==-1)&&!b&&(M("false write response, pause",m._readableState.awaitDrain),m._readableState.awaitDrain++,v=!0),m.pause())}function p(t){M("onerror",t),l(),e.removeListener("error",p),0===D(e,"error")&&e.emit("error",t)}function c(){e.removeListener("finish",d),l()}function d(){M("onfinish"),e.removeListener("close",c),l()}function l(){M("unpipe"),m.unpipe(e)}var m=this,u=this._readableState;switch(u.pipesCount){case 0:u.pipes=e;break;case 1:u.pipes=[u.pipes,e];break;default:u.pipes.push(e)}u.pipesCount+=1,M("pipe count=%d opts=%j",u.pipesCount,n);var h=(!n||n.end!==!1)&&e!==t.stdout&&e!==t.stderr,f=h?o:l;u.endEmitted?O(f):m.once("end",f),e.on("unpipe",i);var g=y(m);e.on("drain",g);var b=!1,v=!1;return m.on("data",s),r(e,"error",p),e.once("close",c),e.once("finish",d),e.emit("pipe",m),u.flowing||(M("pipe resume"),m.resume()),e},o.prototype.unpipe=function(e){var t=this._readableState;if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this),this);if(!e){var n=t.pipes,r=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i0?this.tail.next=t:this.head=t,this.tail=t,++this.length},r.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},r.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},r.prototype.clear=function(){this.head=this.tail=null,this.length=0},r.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n},r.prototype.concat=function(e){if(0===this.length)return i.alloc(0);if(1===this.length)return this.head.data;for(var t=i.allocUnsafe(e>>>0),n=this.head,r=0;n;)n.data.copy(t,r),r+=n.data.length,n=n.next;return t}},function(e,t,n){"use strict";function r(e){return this instanceof r?(c.call(this,e),d.call(this,e),e&&e.readable===!1&&(this.readable=!1),e&&e.writable===!1&&(this.writable=!1),this.allowHalfOpen=!0,e&&e.allowHalfOpen===!1&&(this.allowHalfOpen=!1),void this.once("end",i)):new r(e)}function i(){this.allowHalfOpen||this._writableState.ended||s(o,this)}function o(e){e.end()}var a=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};e.exports=r;var s=n(15),p=n(18);p.inherits=n(11);var c=n(14),d=n(22);p.inherits(r,c);for(var l=a(d.prototype),m=0;m-1?r:R;s.WritableState=a;var C=n(18);C.inherits=n(11);var $={deprecate:n(25)},O=n(16),E=n(17).Buffer;C.inherits(s,O),a.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(a.prototype,"buffer",{get:$.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.")})}catch(e){}}();var D;"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(D=Function.prototype[Symbol.hasInstance],Object.defineProperty(s,Symbol.hasInstance,{value:function(e){return!!D.call(this,e)||e&&e._writableState instanceof a}})):D=function(e){return e instanceof this},s.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},s.prototype.write=function(e,t,n){var r=this._writableState,o=!1,a=E.isBuffer(e);return"function"==typeof t&&(n=t,t=null),a?t="buffer":t||(t=r.defaultEncoding),"function"!=typeof n&&(n=i),r.ended?p(this,n):(a||c(this,r,e,n))&&(r.pendingcb++,o=l(this,r,a,e,t,n)),o},s.prototype.cork=function(){var e=this._writableState;e.corked++},s.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,e.writing||e.corked||e.finished||e.bufferProcessing||!e.bufferedRequest||b(this,e))},s.prototype.setDefaultEncoding=function(e){if("string"==typeof e&&(e=e.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())>-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},s.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},s.prototype._writev=null,s.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!==e&&void 0!==e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||x(this,r,n)}}).call(t,n(1),n(23).setImmediate)},function(e,t,n){function r(e,t){this._id=e,this._clearFn=t}var i=Function.prototype.apply;t.setTimeout=function(){return new r(i.call(setTimeout,window,arguments),clearTimeout)},t.setInterval=function(){return new r(i.call(setInterval,window,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},r.prototype.unref=r.prototype.ref=function(){},r.prototype.close=function(){this._clearFn.call(window,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(24),t.setImmediate=setImmediate,t.clearImmediate=clearImmediate},function(e,t,n){(function(e,t){!function(e,n){"use strict";function r(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n>5===6?2:e>>4===14?3:e>>3===30?4:-1}function s(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0))}function p(e,t,n){if(128!==(192&t[0]))return e.lastNeed=0,"�".repeat(n);if(e.lastNeed>1&&t.length>1){if(128!==(192&t[1]))return e.lastNeed=1,"�".repeat(n+1);if(e.lastNeed>2&&t.length>2&&128!==(192&t[2]))return e.lastNeed=2, +"�".repeat(n+2)}}function c(e){var t=this.lastTotal-this.lastNeed,n=p(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function d(e,t){var n=s(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function l(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�".repeat(this.lastTotal-this.lastNeed):t}function m(e,t){if((e.length-t)%2===0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function u(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function h(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function y(e){return e.toString(this.encoding)}function g(e){return e&&e.length?this.write(e):""}var b=n(17).Buffer,v=b.isEncoding||function(e){switch(e=""+e,e&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};t.StringDecoder=o,o.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(t=this.fillLast(e),void 0===t)return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n",'"',"`"," ","\r","\n","\t"],h=["{","}","|","\\","^","`"].concat(u),f=["'"].concat(h),y=["%","/","?",";","#"].concat(f),g=["/","?","#"],b=255,v=/^[+a-z0-9A-Z_-]{0,63}$/,w=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,S={javascript:!0,"javascript:":!0},x={javascript:!0,"javascript:":!0},I={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},T=n(36);r.prototype.parse=function(e,t,n){if(!c.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var r=e.indexOf("?"),i=r!==-1&&r127?"x":P[M];if(!N.match(v)){var _=j.slice(0,C),q=j.slice(C+1),U=P.match(w);U&&(_.push(U[1]),q.unshift(U[2])),q.length&&(s="/"+q.join(".")+s),this.hostname=_.join(".");break}}}this.hostname.length>b?this.hostname="":this.hostname=this.hostname.toLowerCase(),D||(this.hostname=p.toASCII(this.hostname));var F=this.port?":"+this.port:"",B=this.hostname||"";this.host=B+F,this.href+=this.host,D&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==s[0]&&(s="/"+s))}if(!S[h])for(var C=0,A=f.length;C0)&&n.host.split("@");R&&(n.auth=R.shift(),n.host=n.hostname=R.shift())}return n.search=e.search,n.query=e.query,c.isNull(n.pathname)&&c.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!S.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var k=S.slice(-1)[0],C=(n.host||e.host||S.length>1)&&("."===k||".."===k)||""===k,$=0,O=S.length;O>=0;O--)k=S[O],"."===k?S.splice(O,1):".."===k?(S.splice(O,1),$++):$&&(S.splice(O,1),$--);if(!v&&!w)for(;$--;$)S.unshift("..");!v||""===S[0]||S[0]&&"/"===S[0].charAt(0)||S.unshift(""),C&&"/"!==S.join("/").substr(-1)&&S.push("");var E=""===S[0]||S[0]&&"/"===S[0].charAt(0);if(T){n.hostname=n.host=E?"":S.length?S.shift():"";var R=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@");R&&(n.auth=R.shift(),n.host=n.hostname=R.shift())}return v=v||n.host&&S.length,v&&!E&&S.unshift(""),S.length?n.pathname=S.join("/"):(n.pathname=null,n.path=null),c.isNull(n.pathname)&&c.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=e.auth||n.auth,n.slashes=n.slashes||e.slashes,n.href=n.format(),n},r.prototype.parseHost=function(){var e=this.host,t=l.exec(e);t&&(t=t[0],":"!==t&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},function(e,t,n){var r;(function(e,i){!function(o){function a(e){throw RangeError(j[e])}function s(e,t){for(var n=e.length,r=[];n--;)r[n]=t(e[n]);return r}function p(e,t){var n=e.split("@"),r="";n.length>1&&(r=n[0]+"@",e=n[1]),e=e.replace(D,".");var i=e.split("."),o=s(i,t).join(".");return r+o}function c(e){for(var t,n,r=[],i=0,o=e.length;i=55296&&t<=56319&&i65535&&(e-=65536,t+=N(e>>>10&1023|55296),e=56320|1023&e),t+=N(e)}).join("")}function l(e){return e-48<10?e-22:e-65<26?e-65:e-97<26?e-97:S}function m(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function u(e,t,n){var r=0;for(e=n?P(e/R):e>>1,e+=P(e/t);e>A*I>>1;r+=S)e=P(e/A);return P(r+(A+1)*e/(e+T))}function h(e){var t,n,r,i,o,s,p,c,m,h,f=[],y=e.length,g=0,b=C,v=k;for(n=e.lastIndexOf($),n<0&&(n=0),r=0;r=128&&a("not-basic"),f.push(e.charCodeAt(r));for(i=n>0?n+1:0;i=y&&a("invalid-input"),c=l(e.charCodeAt(i++)),(c>=S||c>P((w-g)/s))&&a("overflow"),g+=c*s,m=p<=v?x:p>=v+I?I:p-v,!(cP(w/h)&&a("overflow"),s*=h;t=f.length+1,v=u(g-o,t,0==o),P(g/t)>w-b&&a("overflow"),b+=P(g/t),g%=t,f.splice(g++,0,b)}return d(f)}function f(e){var t,n,r,i,o,s,p,d,l,h,f,y,g,b,v,T=[];for(e=c(e),y=e.length,t=C,n=0,o=k,s=0;s=t&&fP((w-n)/g)&&a("overflow"),n+=(p-t)*g,t=p,s=0;sw&&a("overflow"),f==t){for(d=n,l=S;h=l<=o?x:l>=o+I?I:l-o,!(d= 0x80 (not a basic code point)","invalid-input":"Invalid input"},A=S-x,P=Math.floor,N=String.fromCharCode;v={version:"1.3.2",ucs2:{decode:c,encode:d},decode:h,encode:f,toASCII:g,toUnicode:y},r=function(){return v}.call(t,n,t,e),!(void 0!==r&&(e.exports=r))}(this)}).call(t,n(34)(e),function(){return this}())},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children=[],e.webpackPolyfill=1),e}},function(e,t){"use strict";e.exports={isString:function(e){return"string"==typeof e},isObject:function(e){return"object"==typeof e&&null!==e},isNull:function(e){return null===e},isNullOrUndefined:function(e){return null==e}}},function(e,t,n){"use strict";t.decode=t.parse=n(37),t.encode=t.stringify=n(38)},function(e,t){"use strict";function n(e,t){return Object.prototype.hasOwnProperty.call(e,t)}e.exports=function(e,t,r,i){t=t||"&",r=r||"=";var o={};if("string"!=typeof e||0===e.length)return o;var a=/\+/g;e=e.split(t);var s=1e3;i&&"number"==typeof i.maxKeys&&(s=i.maxKeys);var p=e.length;s>0&&p>s&&(p=s);for(var c=0;c=0?(d=h.substr(0,f),l=h.substr(f+1)):(d=h,l=""),m=decodeURIComponent(d),u=decodeURIComponent(l),n(o,m)?Array.isArray(o[m])?o[m].push(u):o[m]=[o[m],u]:o[m]=u}return o}},function(e,t){"use strict";var n=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};e.exports=function(e,t,r,i){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?Object.keys(e).map(function(i){var o=encodeURIComponent(n(i))+r;return Array.isArray(e[i])?e[i].map(function(e){return o+encodeURIComponent(n(e))}).join(t):o+encodeURIComponent(n(e[i]))}).join(t):i?encodeURIComponent(n(i))+r+encodeURIComponent(n(e)):""}},function(e,t,n){var r=n(8),i=e.exports;for(var o in r)r.hasOwnProperty(o)&&(i[o]=r[o]);i.request=function(e,t){return e||(e={}),e.scheme="https",e.protocol="https:",r.request.call(this,e,t)}},function(e,t){"use strict";e.exports.HOST="localhost",e.exports.PORT=9222},function(e,t){"use strict";function n(e,t,n){var r=e.get(t,function(e){var t="";e.on("data",function(e){t+=e}),e.on("end",function(){200===e.statusCode?n(null,t):n(new Error(t))})});r.on("error",function(e){n(e)})}e.exports=n},function(e,t){e.exports={version:{major:"1",minor:"2"},domains:[{domain:"Inspector",experimental:!0,types:[],commands:[{name:"enable",description:"Enables inspector domain notifications."},{name:"disable",description:"Disables inspector domain notifications."}],events:[{name:"detached",description:"Fired when remote debugging connection is about to be terminated. Contains detach reason.",parameters:[{name:"reason",type:"string",description:"The reason why connection has been terminated."}]},{name:"targetCrashed",description:"Fired when debugging target has crashed"}]},{domain:"Memory",experimental:!0,types:[{id:"PressureLevel",type:"string",enum:["moderate","critical"],description:"Memory pressure level."}],commands:[{name:"getDOMCounters",returns:[{name:"documents",type:"integer"},{name:"nodes",type:"integer"},{name:"jsEventListeners",type:"integer"}]},{name:"setPressureNotificationsSuppressed",description:"Enable/disable suppressing memory pressure notifications in all processes.",parameters:[{name:"suppressed",type:"boolean",description:"If true, memory pressure notifications will be suppressed."}]},{name:"simulatePressureNotification",description:"Simulate a memory pressure notification in all processes.",parameters:[{name:"level",$ref:"PressureLevel",description:"Memory pressure level of the notification."}]}]},{domain:"Page",description:"Actions and events related to the inspected page belong to the page domain.",dependencies:["Debugger","DOM"],types:[{id:"ResourceType",type:"string",enum:["Document","Stylesheet","Image","Media","Font","Script","TextTrack","XHR","Fetch","EventSource","WebSocket","Manifest","Other"],description:"Resource type as it was perceived by the rendering engine."},{id:"FrameId",type:"string",description:"Unique frame identifier."},{id:"Frame",type:"object",description:"Information about the Frame on the page.",properties:[{name:"id",type:"string",description:"Frame unique identifier."},{name:"parentId",type:"string",optional:!0,description:"Parent frame identifier."},{name:"loaderId",$ref:"Network.LoaderId",description:"Identifier of the loader associated with this frame."},{name:"name",type:"string",optional:!0,description:"Frame's name as specified in the tag."},{name:"url",type:"string",description:"Frame document's URL."},{name:"securityOrigin",type:"string",description:"Frame document's security origin."},{name:"mimeType",type:"string",description:"Frame document's mimeType as determined by the browser."}]},{id:"FrameResource",type:"object",description:"Information about the Resource on the page.",properties:[{name:"url",type:"string",description:"Resource URL."},{name:"type",$ref:"ResourceType",description:"Type of this resource."},{name:"mimeType",type:"string",description:"Resource mimeType as determined by the browser."},{name:"lastModified",$ref:"Network.Timestamp",description:"last-modified timestamp as reported by server.",optional:!0},{name:"contentSize",type:"number",description:"Resource content size.",optional:!0},{name:"failed",type:"boolean",optional:!0,description:"True if the resource failed to load."},{name:"canceled",type:"boolean",optional:!0,description:"True if the resource was canceled during loading."}],experimental:!0},{id:"FrameResourceTree",type:"object",description:"Information about the Frame hierarchy along with their cached resources.",properties:[{name:"frame",$ref:"Frame",description:"Frame information for this tree item."},{name:"childFrames",type:"array",optional:!0,items:{$ref:"FrameResourceTree"},description:"Child frames."},{name:"resources",type:"array",items:{$ref:"FrameResource"},description:"Information about frame resources."}],experimental:!0},{id:"ScriptIdentifier",type:"string",description:"Unique script identifier.",experimental:!0},{id:"TransitionType",type:"string",description:"Transition type.",experimental:!0,enum:["link","typed","auto_bookmark","auto_subframe","manual_subframe","generated","auto_toplevel","form_submit","reload","keyword","keyword_generated","other"]},{id:"NavigationEntry",type:"object",description:"Navigation history entry.",properties:[{name:"id",type:"integer",description:"Unique id of the navigation history entry."},{name:"url",type:"string",description:"URL of the navigation history entry."},{name:"userTypedURL",type:"string",description:"URL that the user typed in the url bar."},{name:"title",type:"string",description:"Title of the navigation history entry."},{name:"transitionType",$ref:"TransitionType",description:"Transition type."}],experimental:!0},{id:"ScreencastFrameMetadata",type:"object",description:"Screencast frame metadata.",properties:[{name:"offsetTop",type:"number",experimental:!0,description:"Top offset in DIP."},{name:"pageScaleFactor",type:"number",experimental:!0,description:"Page scale factor."},{name:"deviceWidth",type:"number",experimental:!0,description:"Device screen width in DIP."},{name:"deviceHeight",type:"number",experimental:!0,description:"Device screen height in DIP."},{name:"scrollOffsetX",type:"number",experimental:!0,description:"Position of horizontal scroll in CSS pixels."},{name:"scrollOffsetY",type:"number",experimental:!0,description:"Position of vertical scroll in CSS pixels."},{name:"timestamp",type:"number",optional:!0,experimental:!0,description:"Frame swap timestamp."}],experimental:!0},{id:"DialogType",description:"Javascript dialog type.",type:"string",enum:["alert","confirm","prompt","beforeunload"],experimental:!0},{id:"AppManifestError",description:"Error while paring app manifest.",type:"object",properties:[{name:"message",type:"string",description:"Error message."},{name:"critical",type:"integer",description:"If criticial, this is a non-recoverable parse error."},{name:"line",type:"integer",description:"Error line."},{name:"column",type:"integer",description:"Error column."}],experimental:!0},{id:"NavigationResponse",description:"Proceed: allow the navigation; Cancel: cancel the navigation; CancelAndIgnore: cancels the navigation and makes the requester of the navigation acts like the request was never made.",type:"string",enum:["Proceed","Cancel","CancelAndIgnore"],experimental:!0},{id:"LayoutViewport",type:"object",description:"Layout viewport position and dimensions.",experimental:!0,properties:[{name:"pageX",type:"integer",description:"Horizontal offset relative to the document (CSS pixels)."},{name:"pageY",type:"integer",description:"Vertical offset relative to the document (CSS pixels)."},{name:"clientWidth",type:"integer",description:"Width (CSS pixels), excludes scrollbar if present."},{name:"clientHeight",type:"integer",description:"Height (CSS pixels), excludes scrollbar if present."}]},{id:"VisualViewport",type:"object",description:"Visual viewport position, dimensions, and scale.",experimental:!0,properties:[{name:"offsetX",type:"number",description:"Horizontal offset relative to the layout viewport (CSS pixels)."},{name:"offsetY",type:"number",description:"Vertical offset relative to the layout viewport (CSS pixels)."},{name:"pageX",type:"number",description:"Horizontal offset relative to the document (CSS pixels)."},{name:"pageY",type:"number",description:"Vertical offset relative to the document (CSS pixels)."},{name:"clientWidth",type:"number",description:"Width (CSS pixels), excludes scrollbar if present."},{name:"clientHeight",type:"number",description:"Height (CSS pixels), excludes scrollbar if present."},{name:"scale",type:"number",description:"Scale relative to the ideal viewport (size at width=device-width)."}]}],commands:[{name:"enable",description:"Enables page domain notifications."},{name:"disable",description:"Disables page domain notifications."},{name:"addScriptToEvaluateOnLoad",parameters:[{name:"scriptSource",type:"string"}],returns:[{name:"identifier",$ref:"ScriptIdentifier",description:"Identifier of the added script."}],experimental:!0},{name:"removeScriptToEvaluateOnLoad",parameters:[{name:"identifier",$ref:"ScriptIdentifier"}],experimental:!0},{name:"setAutoAttachToCreatedPages",parameters:[{name:"autoAttach",type:"boolean",description:"If true, browser will open a new inspector window for every page created from this one."}],description:"Controls whether browser will open a new inspector window for connected pages.",experimental:!0},{name:"reload",parameters:[{name:"ignoreCache",type:"boolean",optional:!0,description:"If true, browser cache is ignored (as if the user pressed Shift+refresh)."},{name:"scriptToEvaluateOnLoad",type:"string",optional:!0,description:"If set, the script will be injected into all frames of the inspected page after reload."}],description:"Reloads given page optionally ignoring the cache."},{name:"navigate",parameters:[{name:"url",type:"string",description:"URL to navigate the page to."},{name:"referrer",type:"string",optional:!0,experimental:!0,description:"Referrer URL."},{name:"transitionType",$ref:"TransitionType",optional:!0,experimental:!0,description:"Intended transition type."}],returns:[{name:"frameId",$ref:"FrameId",experimental:!0,description:"Frame id that will be navigated."}],description:"Navigates current page to the given URL."},{name:"stopLoading",description:"Force the page stop all navigations and pending resource fetches.",experimental:!0},{name:"getNavigationHistory",returns:[{name:"currentIndex",type:"integer",description:"Index of the current navigation history entry."},{name:"entries",type:"array",items:{$ref:"NavigationEntry"},description:"Array of navigation history entries."}],description:"Returns navigation history for the current page.",experimental:!0},{name:"navigateToHistoryEntry",parameters:[{name:"entryId",type:"integer",description:"Unique id of the entry to navigate to."}],description:"Navigates current page to the given history entry.",experimental:!0},{name:"getCookies",returns:[{name:"cookies",type:"array",items:{$ref:"Network.Cookie"},description:"Array of cookie objects."}],description:"Returns all browser cookies. Depending on the backend support, will return detailed cookie information in the cookies field.",experimental:!0,redirect:"Network"},{name:"deleteCookie",parameters:[{name:"cookieName",type:"string",description:"Name of the cookie to remove."},{name:"url",type:"string",description:"URL to match cooke domain and path."}],description:"Deletes browser cookie with given name, domain and path.",experimental:!0,redirect:"Network"},{name:"getResourceTree",description:"Returns present frame / resource tree structure.",returns:[{name:"frameTree",$ref:"FrameResourceTree",description:"Present frame / resource tree structure."}],experimental:!0},{name:"getResourceContent",description:"Returns content of the given resource.",parameters:[{name:"frameId",$ref:"FrameId",description:"Frame id to get resource for."},{name:"url",type:"string",description:"URL of the resource to get content for."}],returns:[{name:"content",type:"string",description:"Resource content."},{name:"base64Encoded",type:"boolean",description:"True, if content was served as base64."}],experimental:!0},{name:"searchInResource",description:"Searches for given string in resource content.",parameters:[{name:"frameId",$ref:"FrameId",description:"Frame id for resource to search in."},{name:"url",type:"string",description:"URL of the resource to search in."},{name:"query",type:"string",description:"String to search for."},{name:"caseSensitive",type:"boolean",optional:!0,description:"If true, search is case sensitive."},{name:"isRegex",type:"boolean",optional:!0,description:"If true, treats string parameter as regex."}],returns:[{name:"result",type:"array",items:{$ref:"Debugger.SearchMatch"},description:"List of search matches."}],experimental:!0},{name:"setDocumentContent",description:"Sets given markup as the document's HTML.",parameters:[{name:"frameId",$ref:"FrameId",description:"Frame id to set HTML for."},{name:"html",type:"string",description:"HTML content to set."}],experimental:!0},{name:"setDeviceMetricsOverride",description:'Overrides the values of device screen dimensions (window.screen.width, window.screen.height, window.innerWidth, window.innerHeight, and "device-width"/"device-height"-related CSS media query results).',parameters:[{name:"width",type:"integer",description:"Overriding width value in pixels (minimum 0, maximum 10000000). 0 disables the override."},{name:"height",type:"integer",description:"Overriding height value in pixels (minimum 0, maximum 10000000). 0 disables the override."},{name:"deviceScaleFactor",type:"number",description:"Overriding device scale factor value. 0 disables the override."},{name:"mobile",type:"boolean",description:"Whether to emulate mobile device. This includes viewport meta tag, overlay scrollbars, text autosizing and more."},{name:"fitWindow",type:"boolean",description:"Whether a view that exceeds the available browser window area should be scaled down to fit."},{name:"scale",type:"number",optional:!0,description:"Scale to apply to resulting view image. Ignored in |fitWindow| mode."},{name:"offsetX",type:"number",optional:!0,description:"X offset to shift resulting view image by. Ignored in |fitWindow| mode."},{name:"offsetY",type:"number",optional:!0,description:"Y offset to shift resulting view image by. Ignored in |fitWindow| mode."},{name:"screenWidth",type:"integer",optional:!0, +description:"Overriding screen width value in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"screenHeight",type:"integer",optional:!0,description:"Overriding screen height value in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"positionX",type:"integer",optional:!0,description:"Overriding view X position on screen in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"positionY",type:"integer",optional:!0,description:"Overriding view Y position on screen in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"screenOrientation",$ref:"Emulation.ScreenOrientation",optional:!0,description:"Screen orientation override."}],redirect:"Emulation",experimental:!0},{name:"clearDeviceMetricsOverride",description:"Clears the overriden device metrics.",redirect:"Emulation",experimental:!0},{name:"setGeolocationOverride",description:"Overrides the Geolocation Position or Error. Omitting any of the parameters emulates position unavailable.",parameters:[{name:"latitude",type:"number",optional:!0,description:"Mock latitude"},{name:"longitude",type:"number",optional:!0,description:"Mock longitude"},{name:"accuracy",type:"number",optional:!0,description:"Mock accuracy"}],redirect:"Emulation"},{name:"clearGeolocationOverride",description:"Clears the overriden Geolocation Position and Error.",redirect:"Emulation"},{name:"setDeviceOrientationOverride",description:"Overrides the Device Orientation.",parameters:[{name:"alpha",type:"number",description:"Mock alpha"},{name:"beta",type:"number",description:"Mock beta"},{name:"gamma",type:"number",description:"Mock gamma"}],redirect:"DeviceOrientation",experimental:!0},{name:"clearDeviceOrientationOverride",description:"Clears the overridden Device Orientation.",redirect:"DeviceOrientation",experimental:!0},{name:"setTouchEmulationEnabled",parameters:[{name:"enabled",type:"boolean",description:"Whether the touch event emulation should be enabled."},{name:"configuration",type:"string",enum:["mobile","desktop"],optional:!0,description:"Touch/gesture events configuration. Default: current platform."}],description:"Toggles mouse event-based touch event emulation.",experimental:!0,redirect:"Emulation"},{name:"captureScreenshot",description:"Capture page screenshot.",parameters:[{name:"format",type:"string",optional:!0,enum:["jpeg","png"],description:"Image compression format (defaults to png)."},{name:"quality",type:"integer",optional:!0,description:"Compression quality from range [0..100] (jpeg only)."},{name:"fromSurface",type:"boolean",optional:!0,description:"Capture the screenshot from the surface, rather than the view. Defaults to true.",experimental:!0}],returns:[{name:"data",type:"string",description:"Base64-encoded image data."}],experimental:!0},{name:"printToPDF",description:"Print page as PDF.",parameters:[{name:"landscape",type:"boolean",optional:!0,description:"Paper orientation. Defaults to false."},{name:"displayHeaderFooter",type:"boolean",optional:!0,description:"Display header and footer. Defaults to false."},{name:"printBackground",type:"boolean",optional:!0,description:"Print background graphics. Defaults to false."},{name:"scale",type:"number",optional:!0,description:"Scale of the webpage rendering. Defaults to 1."},{name:"paperWidth",type:"number",optional:!0,description:"Paper width in inches. Defaults to 8.5 inches."},{name:"paperHeight",type:"number",optional:!0,description:"Paper height in inches. Defaults to 11 inches."},{name:"marginTop",type:"number",optional:!0,description:"Top margin in inches. Defaults to 1cm (~0.4 inches)."},{name:"marginBottom",type:"number",optional:!0,description:"Bottom margin in inches. Defaults to 1cm (~0.4 inches)."},{name:"marginLeft",type:"number",optional:!0,description:"Left margin in inches. Defaults to 1cm (~0.4 inches)."},{name:"marginRight",type:"number",optional:!0,description:"Right margin in inches. Defaults to 1cm (~0.4 inches)."},{name:"pageRanges",type:"string",optional:!0,description:"Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages."}],returns:[{name:"data",type:"string",description:"Base64-encoded pdf data."}],experimental:!0},{name:"startScreencast",description:"Starts sending each frame using the screencastFrame event.",parameters:[{name:"format",type:"string",optional:!0,enum:["jpeg","png"],description:"Image compression format."},{name:"quality",type:"integer",optional:!0,description:"Compression quality from range [0..100]."},{name:"maxWidth",type:"integer",optional:!0,description:"Maximum screenshot width."},{name:"maxHeight",type:"integer",optional:!0,description:"Maximum screenshot height."},{name:"everyNthFrame",type:"integer",optional:!0,description:"Send every n-th frame."}],experimental:!0},{name:"stopScreencast",description:"Stops sending each frame in the screencastFrame.",experimental:!0},{name:"screencastFrameAck",description:"Acknowledges that a screencast frame has been received by the frontend.",parameters:[{name:"sessionId",type:"integer",description:"Frame number."}],experimental:!0},{name:"handleJavaScriptDialog",description:"Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload).",parameters:[{name:"accept",type:"boolean",description:"Whether to accept or dismiss the dialog."},{name:"promptText",type:"string",optional:!0,description:"The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog."}]},{name:"getAppManifest",experimental:!0,returns:[{name:"url",type:"string",description:"Manifest location."},{name:"errors",type:"array",items:{$ref:"AppManifestError"}},{name:"data",type:"string",optional:!0,description:"Manifest content."}]},{name:"requestAppBanner",experimental:!0},{name:"setControlNavigations",parameters:[{name:"enabled",type:"boolean"}],description:"Toggles navigation throttling which allows programatic control over navigation and redirect response.",experimental:!0},{name:"processNavigation",parameters:[{name:"response",$ref:"NavigationResponse"},{name:"navigationId",type:"integer"}],description:"Should be sent in response to a navigationRequested or a redirectRequested event, telling the browser how to handle the navigation.",experimental:!0},{name:"getLayoutMetrics",description:"Returns metrics relating to the layouting of the page, such as viewport bounds/scale.",experimental:!0,returns:[{name:"layoutViewport",$ref:"LayoutViewport",description:"Metrics relating to the layout viewport."},{name:"visualViewport",$ref:"VisualViewport",description:"Metrics relating to the visual viewport."},{name:"contentSize",$ref:"DOM.Rect",description:"Size of scrollable area."}]},{name:"createIsolatedWorld",description:"Creates an isolated world for the given frame.",experimental:!0,parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame in which the isolated world should be created."},{name:"worldName",type:"string",optional:!0,description:"An optional name which is reported in the Execution Context."},{name:"grantUniveralAccess",type:"boolean",optional:!0,description:"Whether or not universal access should be granted to the isolated world. This is a powerful option, use with caution."}]}],events:[{name:"domContentEventFired",parameters:[{name:"timestamp",type:"number"}]},{name:"loadEventFired",parameters:[{name:"timestamp",type:"number"}]},{name:"frameAttached",description:"Fired when frame has been attached to its parent.",parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame that has been attached."},{name:"parentFrameId",$ref:"FrameId",description:"Parent frame identifier."},{name:"stack",$ref:"Runtime.StackTrace",optional:!0,description:"JavaScript stack trace of when frame was attached, only set if frame initiated from script.",experimental:!0}]},{name:"frameNavigated",description:"Fired once navigation of the frame has completed. Frame is now associated with the new loader.",parameters:[{name:"frame",$ref:"Frame",description:"Frame object."}]},{name:"frameDetached",description:"Fired when frame has been detached from its parent.",parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame that has been detached."}]},{name:"frameStartedLoading",description:"Fired when frame has started loading.",parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame that has started loading."}],experimental:!0},{name:"frameStoppedLoading",description:"Fired when frame has stopped loading.",parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame that has stopped loading."}],experimental:!0},{name:"frameScheduledNavigation",description:"Fired when frame schedules a potential navigation.",parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame that has scheduled a navigation."},{name:"delay",type:"number",description:"Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start."}],experimental:!0},{name:"frameClearedScheduledNavigation",description:"Fired when frame no longer has a scheduled navigation.",parameters:[{name:"frameId",$ref:"FrameId",description:"Id of the frame that has cleared its scheduled navigation."}],experimental:!0},{name:"frameResized",experimental:!0},{name:"javascriptDialogOpening",description:"Fired when a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload) is about to open.",parameters:[{name:"message",type:"string",description:"Message that will be displayed by the dialog."},{name:"type",$ref:"DialogType",description:"Dialog type."}]},{name:"javascriptDialogClosed",description:"Fired when a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload) has been closed.",parameters:[{name:"result",type:"boolean",description:"Whether dialog was confirmed."}]},{name:"screencastFrame",description:"Compressed image data requested by the startScreencast.",parameters:[{name:"data",type:"string",description:"Base64-encoded compressed image."},{name:"metadata",$ref:"ScreencastFrameMetadata",description:"Screencast frame metadata."},{name:"sessionId",type:"integer",description:"Frame number."}],experimental:!0},{name:"screencastVisibilityChanged",description:"Fired when the page with currently enabled screencast was shown or hidden
.",parameters:[{name:"visible",type:"boolean",description:"True if the page is visible."}],experimental:!0},{name:"interstitialShown",description:"Fired when interstitial page was shown"},{name:"interstitialHidden",description:"Fired when interstitial page was hidden"},{name:"navigationRequested",description:"Fired when a navigation is started if navigation throttles are enabled. The navigation will be deferred until processNavigation is called.",parameters:[{name:"isInMainFrame",type:"boolean",description:"Whether the navigation is taking place in the main frame or in a subframe."},{name:"isRedirect",type:"boolean",description:"Whether the navigation has encountered a server redirect or not."},{name:"navigationId",type:"integer"},{name:"url",type:"string",description:"URL of requested navigation."}]}]},{domain:"Overlay",description:"This domain provides various functionality related to drawing atop the inspected page.",dependencies:["DOM","Page","Runtime"],experimental:!0,types:[{id:"HighlightConfig",type:"object",properties:[{name:"showInfo",type:"boolean",optional:!0,description:"Whether the node info tooltip should be shown (default: false)."},{name:"showRulers",type:"boolean",optional:!0,description:"Whether the rulers should be shown (default: false)."},{name:"showExtensionLines",type:"boolean",optional:!0,description:"Whether the extension lines from node to the rulers should be shown (default: false)."},{name:"displayAsMaterial",type:"boolean",optional:!0},{name:"contentColor",$ref:"DOM.RGBA",optional:!0,description:"The content box highlight fill color (default: transparent)."},{name:"paddingColor",$ref:"DOM.RGBA",optional:!0,description:"The padding highlight fill color (default: transparent)."},{name:"borderColor",$ref:"DOM.RGBA",optional:!0,description:"The border highlight fill color (default: transparent)."},{name:"marginColor",$ref:"DOM.RGBA",optional:!0,description:"The margin highlight fill color (default: transparent)."},{name:"eventTargetColor",$ref:"DOM.RGBA",optional:!0,description:"The event target element highlight fill color (default: transparent)."},{name:"shapeColor",$ref:"DOM.RGBA",optional:!0,description:"The shape outside fill color (default: transparent)."},{name:"shapeMarginColor",$ref:"DOM.RGBA",optional:!0,description:"The shape margin fill color (default: transparent)."},{name:"selectorList",type:"string",optional:!0,description:"Selectors to highlight relevant nodes."}],description:"Configuration data for the highlighting of page elements."},{id:"InspectMode",type:"string",enum:["searchForNode","searchForUAShadowDOM","none"]}],commands:[{name:"enable",description:"Enables domain notifications."},{name:"disable",description:"Disables domain notifications."},{name:"setShowPaintRects",description:"Requests that backend shows paint rectangles",parameters:[{name:"result",type:"boolean",description:"True for showing paint rectangles"}]},{name:"setShowDebugBorders",description:"Requests that backend shows debug borders on layers",parameters:[{name:"show",type:"boolean",description:"True for showing debug borders"}]},{name:"setShowFPSCounter",description:"Requests that backend shows the FPS counter",parameters:[{name:"show",type:"boolean",description:"True for showing the FPS counter"}]},{name:"setShowScrollBottleneckRects",description:"Requests that backend shows scroll bottleneck rects",parameters:[{name:"show",type:"boolean",description:"True for showing scroll bottleneck rects"}]},{name:"setShowViewportSizeOnResize",description:"Paints viewport size upon main frame resize.",parameters:[{name:"show",type:"boolean",description:"Whether to paint size or not."}]},{name:"setPausedInDebuggerMessage",parameters:[{name:"message",type:"string",optional:!0,description:"The message to display, also triggers resume and step over controls."}]},{name:"setSuspended",parameters:[{name:"suspended",type:"boolean",description:"Whether overlay should be suspended and not consume any resources until resumed."}]},{name:"setInspectMode",description:"Enters the 'inspect' mode. In this mode, elements that user is hovering over are highlighted. Backend then generates 'inspectNodeRequested' event upon element selection.",parameters:[{name:"mode",$ref:"InspectMode",description:"Set an inspection mode."},{name:"highlightConfig",$ref:"HighlightConfig",optional:!0,description:"A descriptor for the highlight appearance of hovered-over nodes. May be omitted if enabled == false."}]},{name:"highlightRect",description:"Highlights given rectangle. Coordinates are absolute with respect to the main frame viewport.",parameters:[{name:"x",type:"integer",description:"X coordinate"},{name:"y",type:"integer",description:"Y coordinate"},{name:"width",type:"integer",description:"Rectangle width"},{name:"height",type:"integer",description:"Rectangle height"},{name:"color",$ref:"DOM.RGBA",optional:!0,description:"The highlight fill color (default: transparent)."},{name:"outlineColor",$ref:"DOM.RGBA",optional:!0,description:"The highlight outline color (default: transparent)."}]},{name:"highlightQuad",description:"Highlights given quad. Coordinates are absolute with respect to the main frame viewport.",parameters:[{name:"quad",$ref:"DOM.Quad",description:"Quad to highlight"},{name:"color",$ref:"DOM.RGBA",optional:!0,description:"The highlight fill color (default: transparent)."},{name:"outlineColor",$ref:"DOM.RGBA",optional:!0,description:"The highlight outline color (default: transparent)."}]},{name:"highlightNode",description:"Highlights DOM node with given id or with the given JavaScript object wrapper. Either nodeId or objectId must be specified.",parameters:[{name:"highlightConfig",$ref:"HighlightConfig",description:"A descriptor for the highlight appearance."},{name:"nodeId",$ref:"DOM.NodeId",optional:!0,description:"Identifier of the node to highlight."},{name:"backendNodeId",$ref:"DOM.BackendNodeId",optional:!0,description:"Identifier of the backend node to highlight."},{name:"objectId",$ref:"Runtime.RemoteObjectId",optional:!0,description:"JavaScript object id of the node to be highlighted."}]},{name:"highlightFrame",description:"Highlights owner element of the frame with given id.",parameters:[{name:"frameId",$ref:"Page.FrameId",description:"Identifier of the frame to highlight."},{name:"contentColor",$ref:"DOM.RGBA",optional:!0,description:"The content box highlight fill color (default: transparent)."},{name:"contentOutlineColor",$ref:"DOM.RGBA",optional:!0,description:"The content box highlight outline color (default: transparent)."}]},{name:"hideHighlight",description:"Hides any highlight."},{name:"getHighlightObjectForTest",description:"For testing.",parameters:[{name:"nodeId",$ref:"DOM.NodeId",description:"Id of the node to get highlight object for."}],returns:[{name:"highlight",type:"object",description:"Highlight data for the node."}]}],events:[{name:"nodeHighlightRequested",description:"Fired when the node should be highlighted. This happens after call to setInspectMode.",parameters:[{name:"nodeId",$ref:"DOM.NodeId"}]},{name:"inspectNodeRequested",description:"Fired when the node should be inspected. This happens after call to setInspectMode or when user manually inspects an element.",parameters:[{name:"backendNodeId",$ref:"DOM.BackendNodeId",description:"Id of the node to inspect."}]}]},{domain:"Emulation",description:"This domain emulates different environments for the page.",dependencies:["DOM"],types:[{id:"ScreenOrientation",type:"object",description:"Screen orientation.",properties:[{name:"type",type:"string",enum:["portraitPrimary","portraitSecondary","landscapePrimary","landscapeSecondary"],description:"Orientation type."},{name:"angle",type:"integer",description:"Orientation angle."}]},{id:"VirtualTimePolicy",type:"string",enum:["advance","pause","pauseIfNetworkFetchesPending"],experimental:!0,description:"advance: If the scheduler runs out of immediate work, the virtual time base may fast forward to allow the next delayed task (if any) to run; pause: The virtual time base may not advance; pauseIfNetworkFetchesPending: The virtual time base may not advance if there are any pending resource fetches."}],commands:[{name:"setDeviceMetricsOverride",description:'Overrides the values of device screen dimensions (window.screen.width, window.screen.height, window.innerWidth, window.innerHeight, and "device-width"/"device-height"-related CSS media query results).',parameters:[{name:"width",type:"integer",description:"Overriding width value in pixels (minimum 0, maximum 10000000). 0 disables the override."},{name:"height",type:"integer",description:"Overriding height value in pixels (minimum 0, maximum 10000000). 0 disables the override."},{name:"deviceScaleFactor",type:"number",description:"Overriding device scale factor value. 0 disables the override."},{name:"mobile",type:"boolean",description:"Whether to emulate mobile device. This includes viewport meta tag, overlay scrollbars, text autosizing and more."},{name:"fitWindow",type:"boolean",description:"Whether a view that exceeds the available browser window area should be scaled down to fit."},{name:"scale",type:"number",optional:!0,experimental:!0,description:"Scale to apply to resulting view image. Ignored in |fitWindow| mode."},{name:"offsetX",type:"number",optional:!0,deprecated:!0,experimental:!0,description:"Not used."},{name:"offsetY",type:"number",optional:!0,deprecated:!0,experimental:!0,description:"Not used."},{name:"screenWidth",type:"integer",optional:!0,experimental:!0,description:"Overriding screen width value in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"screenHeight",type:"integer",optional:!0,experimental:!0,description:"Overriding screen height value in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"positionX",type:"integer",optional:!0,experimental:!0,description:"Overriding view X position on screen in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"positionY",type:"integer",optional:!0,experimental:!0,description:"Overriding view Y position on screen in pixels (minimum 0, maximum 10000000). Only used for |mobile==true|."},{name:"screenOrientation",$ref:"ScreenOrientation",optional:!0,description:"Screen orientation override."}]},{name:"clearDeviceMetricsOverride",description:"Clears the overriden device metrics."},{name:"forceViewport",description:"Overrides the visible area of the page. The change is hidden from the page, i.e. the observable scroll position and page scale does not change. In effect, the command moves the specified area of the page into the top-left corner of the frame.",experimental:!0,parameters:[{name:"x",type:"number",description:"X coordinate of top-left corner of the area (CSS pixels)."},{name:"y",type:"number",description:"Y coordinate of top-left corner of the area (CSS pixels)."},{name:"scale",type:"number",description:"Scale to apply to the area (relative to a page scale of 1.0)."}]},{name:"resetViewport",description:"Resets the visible area of the page to the original viewport, undoing any effects of the forceViewport command.",experimental:!0},{name:"resetPageScaleFactor",experimental:!0,description:"Requests that page scale factor is reset to initial values."},{name:"setPageScaleFactor",description:"Sets a specified page scale factor.",experimental:!0,parameters:[{name:"pageScaleFactor",type:"number",description:"Page scale factor."}]},{name:"setVisibleSize",description:"Resizes the frame/viewport of the page. Note that this does not affect the frame's container (e.g. browser window). Can be used to produce screenshots of the specified size. Not supported on Android.",experimental:!0,parameters:[{name:"width",type:"integer",description:"Frame width (DIP)."},{name:"height",type:"integer",description:"Frame height (DIP)."}]},{name:"setScriptExecutionDisabled",description:"Switches script execution in the page.",experimental:!0,parameters:[{name:"value",type:"boolean",description:"Whether script execution should be disabled in the page."}]},{name:"setGeolocationOverride",description:"Overrides the Geolocation Position or Error. Omitting any of the parameters emulates position unavailable.",experimental:!0,parameters:[{name:"latitude",type:"number",optional:!0,description:"Mock latitude"},{name:"longitude",type:"number",optional:!0,description:"Mock longitude"},{name:"accuracy",type:"number",optional:!0,description:"Mock accuracy"}]},{name:"clearGeolocationOverride",description:"Clears the overriden Geolocation Position and Error.",experimental:!0},{name:"setTouchEmulationEnabled",parameters:[{name:"enabled",type:"boolean",description:"Whether the touch event emulation should be enabled."},{name:"configuration",type:"string",enum:["mobile","desktop"],optional:!0,description:"Touch/gesture events configuration. Default: current platform."}],description:"Toggles mouse event-based touch event emulation."},{name:"setEmulatedMedia",parameters:[{name:"media",type:"string",description:"Media type to emulate. Empty string disables the override."}],description:"Emulates the given media for CSS media queries."},{name:"setCPUThrottlingRate",parameters:[{name:"rate",type:"number",description:"Throttling rate as a slowdown factor (1 is no throttle, 2 is 2x slowdown, etc)."}],experimental:!0,description:"Enables CPU throttling to emulate slow CPUs."},{name:"canEmulate",description:"Tells whether emulation is supported.",returns:[{name:"result",type:"boolean",description:"True if emulation is supported."}],experimental:!0},{name:"setVirtualTimePolicy",description:"Turns on virtual time for all frames (replacing real-time with a synthetic time source) and sets the current virtual time policy. Note this supersedes any previous time budget.",parameters:[{name:"policy",$ref:"VirtualTimePolicy"},{name:"budget",type:"integer",optional:!0,description:"If set, after this many virtual milliseconds have elapsed virtual time will be paused and a virtualTimeBudgetExpired event is sent."}],experimental:!0},{name:"setDefaultBackgroundColorOverride",description:"Sets or clears an override of the default background color of the frame. This override is used if the content does not specify one.",parameters:[{name:"color",$ref:"DOM.RGBA",optional:!0,description:"RGBA of the default background color. If not specified, any existing override will be cleared."}],experimental:!0}],events:[{name:"virtualTimeBudgetExpired",experimental:!0,description:"Notification sent after the virual time budget for the current VirtualTimePolicy has run out."}]},{domain:"Security",description:"Security",experimental:!0,types:[{id:"CertificateId",type:"integer",description:"An internal certificate ID value."},{id:"SecurityState",type:"string",enum:["unknown","neutral","insecure","warning","secure","info"],description:"The security level of a page or resource."},{id:"SecurityStateExplanation",type:"object",properties:[{name:"securityState",$ref:"SecurityState",description:"Security state representing the severity of the factor being explained."},{name:"summary",type:"string",description:"Short phrase describing the type of factor."},{name:"description",type:"string",description:"Full text explanation of the factor."},{name:"hasCertificate",type:"boolean",description:"True if the page has a certificate."}],description:"An explanation of an factor contributing to the security state."},{id:"InsecureContentStatus",type:"object",properties:[{name:"ranMixedContent",type:"boolean",description:"True if the page was loaded over HTTPS and ran mixed (HTTP) content such as scripts."},{name:"displayedMixedContent",type:"boolean",description:"True if the page was loaded over HTTPS and displayed mixed (HTTP) content such as images."},{name:"containedMixedForm",type:"boolean",description:"True if the page was loaded over HTTPS and contained a form targeting an insecure url."},{name:"ranContentWithCertErrors",type:"boolean",description:"True if the page was loaded over HTTPS without certificate errors, and ran content such as scripts that were loaded with certificate errors."},{name:"displayedContentWithCertErrors",type:"boolean",description:"True if the page was loaded over HTTPS without certificate errors, and displayed content such as images that were loaded with certificate errors."},{name:"ranInsecureContentStyle",$ref:"SecurityState",description:"Security state representing a page that ran insecure content."},{name:"displayedInsecureContentStyle",$ref:"SecurityState",description:"Security state representing a page that displayed insecure content."}],description:"Information about insecure content on the page."},{id:"CertificateErrorAction",type:"string",enum:["continue","cancel"],description:"The action to take when a certificate error occurs. continue will continue processing the request and cancel will cancel the request."}],commands:[{name:"enable",description:"Enables tracking security state changes."},{name:"disable",description:"Disables tracking security state changes."},{name:"showCertificateViewer",description:"Displays native dialog with the certificate details."},{name:"handleCertificateError",description:"Handles a certificate error that fired a certificateError event.",parameters:[{name:"eventId",type:"integer",description:"The ID of the event."},{name:"action",$ref:"CertificateErrorAction",description:"The action to take on the certificate error."}]},{name:"setOverrideCertificateErrors",description:"Enable/disable overriding certificate errors. If enabled, all certificate error events need to be handled by the DevTools client and should be answered with handleCertificateError commands.",parameters:[{name:"override",type:"boolean",description:"If true, certificate errors will be overridden."}]}],events:[{name:"securityStateChanged",description:"The security state of the page changed.",parameters:[{name:"securityState",$ref:"SecurityState",description:"Security state."},{name:"schemeIsCryptographic",type:"boolean",description:"True if the page was loaded over cryptographic transport such as HTTPS."},{name:"explanations",type:"array",items:{$ref:"SecurityStateExplanation"},description:"List of explanations for the security state. If the overall security state is `insecure` or `warning`, at least one corresponding explanation should be included."},{name:"insecureContentStatus",$ref:"InsecureContentStatus",description:"Information about insecure content on the page."},{name:"summary",type:"string",description:"Overrides user-visible description of the state.",optional:!0}]},{name:"certificateError",description:"There is a certificate error. If overriding certificate errors is enabled, then it should be handled with the handleCertificateError command. Note: this event does not fire if the certificate error has been allowed internally.",parameters:[{name:"eventId",type:"integer",description:"The ID of the event."},{name:"errorType",type:"string",description:"The type of the error."},{name:"requestURL",type:"string",description:"The url that was requested."}]}]},{domain:"Network",description:"Network domain allows tracking network activities of the page. It exposes information about http, file, data and other requests and responses, their headers, bodies, timing, etc.",dependencies:["Runtime","Security"],types:[{id:"LoaderId",type:"string",description:"Unique loader identifier."},{id:"RequestId",type:"string",description:"Unique request identifier."},{id:"InterceptionId",type:"string",description:"Unique intercepted request identifier."},{id:"ErrorReason",type:"string",enum:["Failed","Aborted","TimedOut","AccessDenied","ConnectionClosed","ConnectionReset","ConnectionRefused","ConnectionAborted","ConnectionFailed","NameNotResolved","InternetDisconnected","AddressUnreachable"],description:"Network level fetch failure reason."},{id:"Timestamp",type:"number",description:"Number of seconds since epoch."},{id:"Headers",type:"object",description:"Request / response headers as keys / values of JSON object."},{id:"ConnectionType",type:"string",enum:["none","cellular2g","cellular3g","cellular4g","bluetooth","ethernet","wifi","wimax","other"],description:"Loading priority of a resource request."},{id:"CookieSameSite",type:"string",enum:["Strict","Lax"],description:"Represents the cookie's 'SameSite' status: https://tools.ietf.org/html/draft-west-first-party-cookies"},{id:"ResourceTiming",type:"object",description:"Timing information for the request.",properties:[{name:"requestTime",type:"number",description:"Timing's requestTime is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this requestTime."},{name:"proxyStart",type:"number",description:"Started resolving proxy."},{name:"proxyEnd",type:"number",description:"Finished resolving proxy."},{name:"dnsStart",type:"number",description:"Started DNS address resolve."},{name:"dnsEnd",type:"number",description:"Finished DNS address resolve."},{name:"connectStart",type:"number",description:"Started connecting to the remote host."},{name:"connectEnd",type:"number",description:"Connected to the remote host."},{name:"sslStart",type:"number",description:"Started SSL handshake."},{name:"sslEnd",type:"number",description:"Finished SSL handshake."},{name:"workerStart",type:"number",description:"Started running ServiceWorker.",experimental:!0},{name:"workerReady",type:"number",description:"Finished Starting ServiceWorker.",experimental:!0},{name:"sendStart",type:"number",description:"Started sending request."},{name:"sendEnd",type:"number",description:"Finished sending request." +},{name:"pushStart",type:"number",description:"Time the server started pushing request.",experimental:!0},{name:"pushEnd",type:"number",description:"Time the server finished pushing request.",experimental:!0},{name:"receiveHeadersEnd",type:"number",description:"Finished receiving response headers."}]},{id:"ResourcePriority",type:"string",enum:["VeryLow","Low","Medium","High","VeryHigh"],description:"Loading priority of a resource request."},{id:"Request",type:"object",description:"HTTP request data.",properties:[{name:"url",type:"string",description:"Request URL."},{name:"method",type:"string",description:"HTTP request method."},{name:"headers",$ref:"Headers",description:"HTTP request headers."},{name:"postData",type:"string",optional:!0,description:"HTTP POST request data."},{name:"mixedContentType",optional:!0,type:"string",enum:["blockable","optionally-blockable","none"],description:"The mixed content status of the request, as defined in http://www.w3.org/TR/mixed-content/"},{name:"initialPriority",$ref:"ResourcePriority",description:"Priority of the resource request at the time request is sent."},{name:"referrerPolicy",type:"string",enum:["unsafe-url","no-referrer-when-downgrade","no-referrer","origin","origin-when-cross-origin","no-referrer-when-downgrade-origin-when-cross-origin"],description:"The referrer policy of the request, as defined in https://www.w3.org/TR/referrer-policy/"},{name:"isLinkPreload",type:"boolean",optional:!0,description:"Whether is loaded via link preload."}]},{id:"SignedCertificateTimestamp",type:"object",description:"Details of a signed certificate timestamp (SCT).",properties:[{name:"status",type:"string",description:"Validation status."},{name:"origin",type:"string",description:"Origin."},{name:"logDescription",type:"string",description:"Log name / description."},{name:"logId",type:"string",description:"Log ID."},{name:"timestamp",$ref:"Timestamp",description:"Issuance date."},{name:"hashAlgorithm",type:"string",description:"Hash algorithm."},{name:"signatureAlgorithm",type:"string",description:"Signature algorithm."},{name:"signatureData",type:"string",description:"Signature data."}]},{id:"SecurityDetails",type:"object",description:"Security details about a request.",properties:[{name:"protocol",type:"string",description:'Protocol name (e.g. "TLS 1.2" or "QUIC").'},{name:"keyExchange",type:"string",description:"Key Exchange used by the connection, or the empty string if not applicable."},{name:"keyExchangeGroup",type:"string",optional:!0,description:"(EC)DH group used by the connection, if applicable."},{name:"cipher",type:"string",description:"Cipher name."},{name:"mac",type:"string",optional:!0,description:"TLS MAC. Note that AEAD ciphers do not have separate MACs."},{name:"certificateId",$ref:"Security.CertificateId",description:"Certificate ID value."},{name:"subjectName",type:"string",description:"Certificate subject name."},{name:"sanList",type:"array",items:{type:"string"},description:"Subject Alternative Name (SAN) DNS names and IP addresses."},{name:"issuer",type:"string",description:"Name of the issuing CA."},{name:"validFrom",$ref:"Timestamp",description:"Certificate valid from date."},{name:"validTo",$ref:"Timestamp",description:"Certificate valid to (expiration) date"},{name:"signedCertificateTimestampList",type:"array",items:{$ref:"SignedCertificateTimestamp"},description:"List of signed certificate timestamps (SCTs)."}]},{id:"BlockedReason",type:"string",description:"The reason why request was blocked.",enum:["csp","mixed-content","origin","inspector","subresource-filter","other"],experimental:!0},{id:"Response",type:"object",description:"HTTP response data.",properties:[{name:"url",type:"string",description:"Response URL. This URL can be different from CachedResource.url in case of redirect."},{name:"status",type:"number",description:"HTTP response status code."},{name:"statusText",type:"string",description:"HTTP response status text."},{name:"headers",$ref:"Headers",description:"HTTP response headers."},{name:"headersText",type:"string",optional:!0,description:"HTTP response headers text."},{name:"mimeType",type:"string",description:"Resource mimeType as determined by the browser."},{name:"requestHeaders",$ref:"Headers",optional:!0,description:"Refined HTTP request headers that were actually transmitted over the network."},{name:"requestHeadersText",type:"string",optional:!0,description:"HTTP request headers text."},{name:"connectionReused",type:"boolean",description:"Specifies whether physical connection was actually reused for this request."},{name:"connectionId",type:"number",description:"Physical connection id that was actually used for this request."},{name:"remoteIPAddress",type:"string",optional:!0,experimental:!0,description:"Remote IP address."},{name:"remotePort",type:"integer",optional:!0,experimental:!0,description:"Remote port."},{name:"fromDiskCache",type:"boolean",optional:!0,description:"Specifies that the request was served from the disk cache."},{name:"fromServiceWorker",type:"boolean",optional:!0,description:"Specifies that the request was served from the ServiceWorker."},{name:"encodedDataLength",type:"number",optional:!1,description:"Total number of bytes received for this request so far."},{name:"timing",$ref:"ResourceTiming",optional:!0,description:"Timing information for the given request."},{name:"protocol",type:"string",optional:!0,description:"Protocol used to fetch this request."},{name:"securityState",$ref:"Security.SecurityState",description:"Security state of the request resource."},{name:"securityDetails",$ref:"SecurityDetails",optional:!0,description:"Security details for the request."}]},{id:"WebSocketRequest",type:"object",description:"WebSocket request data.",experimental:!0,properties:[{name:"headers",$ref:"Headers",description:"HTTP request headers."}]},{id:"WebSocketResponse",type:"object",description:"WebSocket response data.",experimental:!0,properties:[{name:"status",type:"number",description:"HTTP response status code."},{name:"statusText",type:"string",description:"HTTP response status text."},{name:"headers",$ref:"Headers",description:"HTTP response headers."},{name:"headersText",type:"string",optional:!0,description:"HTTP response headers text."},{name:"requestHeaders",$ref:"Headers",optional:!0,description:"HTTP request headers."},{name:"requestHeadersText",type:"string",optional:!0,description:"HTTP request headers text."}]},{id:"WebSocketFrame",type:"object",description:"WebSocket frame data.",experimental:!0,properties:[{name:"opcode",type:"number",description:"WebSocket frame opcode."},{name:"mask",type:"boolean",description:"WebSocke frame mask."},{name:"payloadData",type:"string",description:"WebSocke frame payload data."}]},{id:"CachedResource",type:"object",description:"Information about the cached resource.",properties:[{name:"url",type:"string",description:"Resource URL. This is the url of the original network request."},{name:"type",$ref:"Page.ResourceType",description:"Type of this resource."},{name:"response",$ref:"Response",optional:!0,description:"Cached response data."},{name:"bodySize",type:"number",description:"Cached response body size."}]},{id:"Initiator",type:"object",description:"Information about the request initiator.",properties:[{name:"type",type:"string",enum:["parser","script","preload","other"],description:"Type of this initiator."},{name:"stack",$ref:"Runtime.StackTrace",optional:!0,description:"Initiator JavaScript stack trace, set for Script only."},{name:"url",type:"string",optional:!0,description:"Initiator URL, set for Parser type only."},{name:"lineNumber",type:"number",optional:!0,description:"Initiator line number, set for Parser type only (0-based)."}]},{id:"Cookie",type:"object",description:"Cookie object",properties:[{name:"name",type:"string",description:"Cookie name."},{name:"value",type:"string",description:"Cookie value."},{name:"domain",type:"string",description:"Cookie domain."},{name:"path",type:"string",description:"Cookie path."},{name:"expires",type:"number",description:"Cookie expiration date as the number of seconds since the UNIX epoch."},{name:"size",type:"integer",description:"Cookie size."},{name:"httpOnly",type:"boolean",description:"True if cookie is http-only."},{name:"secure",type:"boolean",description:"True if cookie is secure."},{name:"session",type:"boolean",description:"True in case of session cookie."},{name:"sameSite",$ref:"CookieSameSite",optional:!0,description:"Cookie SameSite type."}],experimental:!0}],commands:[{name:"enable",description:"Enables network tracking, network events will now be delivered to the client.",parameters:[{name:"maxTotalBufferSize",type:"integer",optional:!0,experimental:!0,description:"Buffer size in bytes to use when preserving network payloads (XHRs, etc)."},{name:"maxResourceBufferSize",type:"integer",optional:!0,experimental:!0,description:"Per-resource buffer size in bytes to use when preserving network payloads (XHRs, etc)."}]},{name:"disable",description:"Disables network tracking, prevents network events from being sent to the client."},{name:"setUserAgentOverride",description:"Allows overriding user agent with the given string.",parameters:[{name:"userAgent",type:"string",description:"User agent to use."}]},{name:"setExtraHTTPHeaders",description:"Specifies whether to always send extra HTTP headers with the requests from this page.",parameters:[{name:"headers",$ref:"Headers",description:"Map with extra HTTP headers."}]},{name:"getResponseBody",description:"Returns content served for the given request.",parameters:[{name:"requestId",$ref:"RequestId",description:"Identifier of the network request to get content for."}],returns:[{name:"body",type:"string",description:"Response body."},{name:"base64Encoded",type:"boolean",description:"True, if content was sent as base64."}]},{name:"setBlockedURLs",description:"Blocks URLs from loading.",parameters:[{name:"urls",type:"array",items:{type:"string"},description:"URL patterns to block. Wildcards ('*') are allowed."}],experimental:!0},{name:"replayXHR",description:"This method sends a new XMLHttpRequest which is identical to the original one. The following parameters should be identical: method, url, async, request body, extra headers, withCredentials attribute, user, password.",parameters:[{name:"requestId",$ref:"RequestId",description:"Identifier of XHR to replay."}],experimental:!0},{name:"canClearBrowserCache",description:"Tells whether clearing browser cache is supported.",returns:[{name:"result",type:"boolean",description:"True if browser cache can be cleared."}]},{name:"clearBrowserCache",description:"Clears browser cache."},{name:"canClearBrowserCookies",description:"Tells whether clearing browser cookies is supported.",returns:[{name:"result",type:"boolean",description:"True if browser cookies can be cleared."}]},{name:"clearBrowserCookies",description:"Clears browser cookies."},{name:"getCookies",parameters:[{name:"urls",type:"array",items:{type:"string"},optional:!0,description:"The list of URLs for which applicable cookies will be fetched"}],returns:[{name:"cookies",type:"array",items:{$ref:"Cookie"},description:"Array of cookie objects."}],description:"Returns all browser cookies for the current URL. Depending on the backend support, will return detailed cookie information in the cookies field.",experimental:!0},{name:"getAllCookies",returns:[{name:"cookies",type:"array",items:{$ref:"Cookie"},description:"Array of cookie objects."}],description:"Returns all browser cookies. Depending on the backend support, will return detailed cookie information in the cookies field.",experimental:!0},{name:"deleteCookie",parameters:[{name:"cookieName",type:"string",description:"Name of the cookie to remove."},{name:"url",type:"string",description:"URL to match cooke domain and path."}],description:"Deletes browser cookie with given name, domain and path.",experimental:!0},{name:"setCookie",parameters:[{name:"url",type:"string",description:"The request-URI to associate with the setting of the cookie. This value can affect the default domain and path values of the created cookie."},{name:"name",type:"string",description:"The name of the cookie."},{name:"value",type:"string",description:"The value of the cookie."},{name:"domain",type:"string",optional:!0,description:"If omitted, the cookie becomes a host-only cookie."},{name:"path",type:"string",optional:!0,description:"Defaults to the path portion of the url parameter."},{name:"secure",type:"boolean",optional:!0,description:"Defaults ot false."},{name:"httpOnly",type:"boolean",optional:!0,description:"Defaults to false."},{name:"sameSite",$ref:"CookieSameSite",optional:!0,description:"Defaults to browser default behavior."},{name:"expirationDate",$ref:"Timestamp",optional:!0,description:"If omitted, the cookie becomes a session cookie."}],returns:[{name:"success",type:"boolean",description:"True if successfully set cookie."}],description:"Sets a cookie with the given cookie data; may overwrite equivalent cookies if they exist.",experimental:!0},{name:"canEmulateNetworkConditions",description:"Tells whether emulation of network conditions is supported.",returns:[{name:"result",type:"boolean",description:"True if emulation of network conditions is supported."}],experimental:!0},{name:"emulateNetworkConditions",description:"Activates emulation of network conditions.",parameters:[{name:"offline",type:"boolean",description:"True to emulate internet disconnection."},{name:"latency",type:"number",description:"Additional latency (ms)."},{name:"downloadThroughput",type:"number",description:"Maximal aggregated download throughput."},{name:"uploadThroughput",type:"number",description:"Maximal aggregated upload throughput."},{name:"connectionType",$ref:"ConnectionType",optional:!0,description:"Connection type if known."}]},{name:"setCacheDisabled",parameters:[{name:"cacheDisabled",type:"boolean",description:"Cache disabled state."}],description:"Toggles ignoring cache for each request. If true, cache will not be used."},{name:"setBypassServiceWorker",parameters:[{name:"bypass",type:"boolean",description:"Bypass service worker and load from network."}],experimental:!0,description:"Toggles ignoring of service worker for each request."},{name:"setDataSizeLimitsForTest",parameters:[{name:"maxTotalSize",type:"integer",description:"Maximum total buffer size."},{name:"maxResourceSize",type:"integer",description:"Maximum per-resource size."}],description:"For testing.",experimental:!0},{name:"getCertificate",description:"Returns the DER-encoded certificate.",parameters:[{name:"origin",type:"string",description:"Origin to get certificate for."}],returns:[{name:"tableNames",type:"array",items:{type:"string"}}],experimental:!0},{name:"enableRequestInterception",parameters:[{name:"enabled",type:"boolean",description:"Whether or not HTTP requests should be intercepted and Network.requestIntercepted events sent."}],experimental:!0},{name:"continueInterceptedRequest",description:"Response to Network.requestIntercepted which either modifies the request to continue with any modifications, or blocks it, or completes it with the provided response bytes. If a network fetch occurs as a result which encounters a redirect an additional Network.requestIntercepted event will be sent with the same InterceptionId.",parameters:[{name:"interceptionId",$ref:"InterceptionId"},{name:"errorReason",$ref:"ErrorReason",optional:!0,description:"If set this causes the request to fail with the given reason."},{name:"rawResponse",type:"string",optional:!0,description:"If set the requests completes using with the provided base64 encoded raw response, including HTTP status line and headers etc..."},{name:"url",type:"string",optional:!0,description:"If set the request url will be modified in a way that's not observable by page."},{name:"method",type:"string",optional:!0,description:"If set this allows the request method to be overridden."},{name:"postData",type:"string",optional:!0,description:"If set this allows postData to be set."},{name:"headers",$ref:"Headers",optional:!0,description:"If set this allows the request headers to be changed."}],experimental:!0}],events:[{name:"resourceChangedPriority",description:"Fired when resource loading priority is changed",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"newPriority",$ref:"ResourcePriority",description:"New priority"},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."}],experimental:!0},{name:"requestWillBeSent",description:"Fired when page is about to send HTTP request.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"frameId",$ref:"Page.FrameId",description:"Frame identifier.",experimental:!0},{name:"loaderId",$ref:"LoaderId",description:"Loader identifier."},{name:"documentURL",type:"string",description:"URL of the document this request is loaded for."},{name:"request",$ref:"Request",description:"Request data."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"wallTime",$ref:"Timestamp",experimental:!0,description:"UTC Timestamp."},{name:"initiator",$ref:"Initiator",description:"Request initiator."},{name:"redirectResponse",optional:!0,$ref:"Response",description:"Redirect response data."},{name:"type",$ref:"Page.ResourceType",optional:!0,experimental:!0,description:"Type of this resource."}]},{name:"requestServedFromCache",description:"Fired if request ended up loading from cache.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."}]},{name:"responseReceived",description:"Fired when HTTP response is available.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"frameId",$ref:"Page.FrameId",description:"Frame identifier.",experimental:!0},{name:"loaderId",$ref:"LoaderId",description:"Loader identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"type",$ref:"Page.ResourceType",description:"Resource type."},{name:"response",$ref:"Response",description:"Response data."}]},{name:"dataReceived",description:"Fired when data chunk was received over the network.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"dataLength",type:"integer",description:"Data chunk length."},{name:"encodedDataLength",type:"integer",description:"Actual bytes received (might be less than dataLength for compressed encodings)."}]},{name:"loadingFinished",description:"Fired when HTTP request has finished loading.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"encodedDataLength",type:"number",description:"Total number of bytes received for this request."}]},{name:"loadingFailed",description:"Fired when HTTP request has failed to load.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"type",$ref:"Page.ResourceType",description:"Resource type."},{name:"errorText",type:"string",description:"User friendly error message."},{name:"canceled",type:"boolean",optional:!0,description:"True if loading was canceled."},{name:"blockedReason",$ref:"BlockedReason",optional:!0,description:"The reason why loading was blocked, if any.",experimental:!0}]},{name:"webSocketWillSendHandshakeRequest",description:"Fired when WebSocket is about to initiate handshake.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"wallTime",$ref:"Timestamp",experimental:!0,description:"UTC Timestamp."},{name:"request",$ref:"WebSocketRequest",description:"WebSocket request data."}],experimental:!0},{name:"webSocketHandshakeResponseReceived",description:"Fired when WebSocket handshake response becomes available.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"response",$ref:"WebSocketResponse",description:"WebSocket response data."}],experimental:!0},{name:"webSocketCreated",description:"Fired upon WebSocket creation.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"url",type:"string",description:"WebSocket request URL."},{name:"initiator",$ref:"Initiator",optional:!0,description:"Request initiator."}],experimental:!0},{name:"webSocketClosed",description:"Fired when WebSocket is closed.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."}],experimental:!0},{name:"webSocketFrameReceived",description:"Fired when WebSocket frame is received.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"response",$ref:"WebSocketFrame",description:"WebSocket response data."}],experimental:!0},{name:"webSocketFrameError",description:"Fired when WebSocket frame error occurs.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"errorMessage",type:"string",description:"WebSocket frame error message."}],experimental:!0},{name:"webSocketFrameSent",description:"Fired when WebSocket frame is sent.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"response",$ref:"WebSocketFrame",description:"WebSocket response data."}],experimental:!0},{name:"eventSourceMessageReceived",description:"Fired when EventSource message is received.",parameters:[{name:"requestId",$ref:"RequestId",description:"Request identifier."},{name:"timestamp",$ref:"Timestamp",description:"Timestamp."},{name:"eventName",type:"string",description:"Message type."},{name:"eventId",type:"string",description:"Message identifier."},{name:"data",type:"string",description:"Message content."}],experimental:!0},{name:"requestIntercepted",description:"Details of an intercepted HTTP request, which must be either allowed, blocked, modified or mocked.",parameters:[{name:"InterceptionId",$ref:"InterceptionId",description:"Each request the page makes will have a unique id, however if any redirects are encountered while processing that fetch, they will be reported with the same id as the original fetch."},{name:"request",$ref:"Request"},{name:"redirectHeaders",$ref:"Headers",optional:!0,description:"HTTP response headers, only sent if a redirect was intercepted."},{name:"redirectStatusCode",type:"integer",optional:!0,description:"HTTP response code, only sent if a redirect was intercepted."},{name:"redirectUrl",optional:!0,type:"string",description:"Redirect location, only sent if a redirect was intercepted."}],experimental:!0}]},{domain:"Database",experimental:!0,types:[{id:"DatabaseId",type:"string",description:"Unique identifier of Database object.",experimental:!0},{id:"Database",type:"object",description:"Database object.",experimental:!0,properties:[{name:"id",$ref:"DatabaseId",description:"Database ID."},{name:"domain",type:"string",description:"Database domain."},{name:"name",type:"string",description:"Database name."},{name:"version",type:"string",description:"Database version."}]},{id:"Error",type:"object",description:"Database error.",properties:[{name:"message",type:"string",description:"Error message."},{name:"code",type:"integer",description:"Error code."}]}],commands:[{name:"enable",description:"Enables database tracking, database events will now be delivered to the client."},{name:"disable",description:"Disables database tracking, prevents database events from being sent to the client."},{name:"getDatabaseTableNames",parameters:[{name:"databaseId",$ref:"DatabaseId"}],returns:[{name:"tableNames",type:"array",items:{type:"string"}}]},{name:"executeSQL",parameters:[{name:"databaseId",$ref:"DatabaseId"},{name:"query",type:"string"}],returns:[{name:"columnNames",type:"array",optional:!0,items:{type:"string"}},{name:"values",type:"array",optional:!0,items:{type:"any"}},{name:"sqlError",$ref:"Error",optional:!0}]}],events:[{name:"addDatabase",parameters:[{name:"database",$ref:"Database"}]}]},{domain:"IndexedDB",dependencies:["Runtime"],experimental:!0,types:[{id:"DatabaseWithObjectStores",type:"object",description:"Database with an array of object stores.",properties:[{name:"name",type:"string",description:"Database name."},{name:"version",type:"integer",description:"Database version."},{name:"objectStores",type:"array",items:{$ref:"ObjectStore"},description:"Object stores in this database."}]},{id:"ObjectStore",type:"object",description:"Object store.",properties:[{name:"name",type:"string",description:"Object store name."},{name:"keyPath",$ref:"KeyPath",description:"Object store key path."},{name:"autoIncrement",type:"boolean",description:"If true, object store has auto increment flag set."},{name:"indexes",type:"array",items:{$ref:"ObjectStoreIndex"},description:"Indexes in this object store."}]},{id:"ObjectStoreIndex",type:"object",description:"Object store index.",properties:[{name:"name",type:"string",description:"Index name."},{name:"keyPath",$ref:"KeyPath",description:"Index key path."},{name:"unique",type:"boolean",description:"If true, index is unique."},{name:"multiEntry",type:"boolean",description:"If true, index allows multiple entries for a key."}]},{id:"Key",type:"object",description:"Key.",properties:[{name:"type",type:"string",enum:["number","string","date","array"],description:"Key type."},{name:"number",type:"number",optional:!0,description:"Number value."},{name:"string",type:"string",optional:!0,description:"String value."},{name:"date",type:"number",optional:!0,description:"Date value."},{name:"array",type:"array",optional:!0,items:{$ref:"Key"},description:"Array value."}]},{id:"KeyRange",type:"object",description:"Key range.",properties:[{name:"lower",$ref:"Key",optional:!0,description:"Lower bound."},{name:"upper",$ref:"Key",optional:!0,description:"Upper bound."},{name:"lowerOpen",type:"boolean",description:"If true lower bound is open."},{name:"upperOpen",type:"boolean",description:"If true upper bound is open."}]},{id:"DataEntry",type:"object",description:"Data entry.",properties:[{name:"key",$ref:"Runtime.RemoteObject",description:"Key object."},{name:"primaryKey",$ref:"Runtime.RemoteObject",description:"Primary key object."},{name:"value",$ref:"Runtime.RemoteObject",description:"Value object."}]},{id:"KeyPath",type:"object",description:"Key path.",properties:[{name:"type",type:"string",enum:["null","string","array"],description:"Key path type."},{name:"string",type:"string",optional:!0,description:"String value."},{name:"array",type:"array",optional:!0,items:{type:"string"},description:"Array value."}]}],commands:[{name:"enable",description:"Enables events from backend."},{name:"disable",description:"Disables events from backend."},{name:"requestDatabaseNames",parameters:[{name:"securityOrigin",type:"string",description:"Security origin."}],returns:[{name:"databaseNames",type:"array",items:{type:"string"},description:"Database names for origin."}],description:"Requests database names for given security origin."},{name:"requestDatabase",parameters:[{name:"securityOrigin",type:"string",description:"Security origin."},{name:"databaseName",type:"string",description:"Database name."}],returns:[{name:"databaseWithObjectStores",$ref:"DatabaseWithObjectStores",description:"Database with an array of object stores."}],description:"Requests database with given name in given frame."},{name:"requestData",parameters:[{name:"securityOrigin",type:"string",description:"Security origin."},{name:"databaseName",type:"string",description:"Database name."},{name:"objectStoreName",type:"string",description:"Object store name."},{name:"indexName",type:"string",description:"Index name, empty string for object store data requests."},{name:"skipCount",type:"integer",description:"Number of records to skip."},{name:"pageSize",type:"integer",description:"Number of records to fetch."},{name:"keyRange",$ref:"KeyRange",optional:!0,description:"Key range."}],returns:[{name:"objectStoreDataEntries",type:"array",items:{$ref:"DataEntry"},description:"Array of object store data entries."},{name:"hasMore",type:"boolean",description:"If true, there are more entries to fetch in the given range."}],description:"Requests data from object store or index."},{name:"clearObjectStore",parameters:[{name:"securityOrigin",type:"string",description:"Security origin."},{name:"databaseName",type:"string",description:"Database name."},{name:"objectStoreName",type:"string",description:"Object store name."}],returns:[],description:"Clears all entries from an object store."},{name:"deleteDatabase",parameters:[{name:"securityOrigin",type:"string",description:"Security origin."},{name:"databaseName",type:"string",description:"Database name."}],returns:[],description:"Deletes a database."}]},{domain:"CacheStorage",experimental:!0,types:[{id:"CacheId",type:"string",description:"Unique identifier of the Cache object."},{id:"DataEntry",type:"object",description:"Data entry.",properties:[{name:"request",type:"string",description:"Request url spec."},{name:"response",type:"string",description:"Response stataus text."}]},{id:"Cache",type:"object",description:"Cache identifier.",properties:[{name:"cacheId",$ref:"CacheId",description:"An opaque unique id of the cache."},{name:"securityOrigin",type:"string",description:"Security origin of the cache."},{name:"cacheName",type:"string",description:"The name of the cache."}]}],commands:[{name:"requestCacheNames",parameters:[{name:"securityOrigin",type:"string",description:"Security origin."}],returns:[{name:"caches",type:"array",items:{$ref:"Cache"},description:"Caches for the security origin."}],description:"Requests cache names."},{name:"requestEntries",parameters:[{name:"cacheId",$ref:"CacheId",description:"ID of cache to get entries from."},{name:"skipCount",type:"integer",description:"Number of records to skip."},{name:"pageSize",type:"integer",description:"Number of records to fetch."}],returns:[{name:"cacheDataEntries",type:"array",items:{$ref:"DataEntry"},description:"Array of object store data entries."},{name:"hasMore",type:"boolean",description:"If true, there are more entries to fetch in the given range."}],description:"Requests data from cache."},{name:"deleteCache",parameters:[{name:"cacheId",$ref:"CacheId",description:"Id of cache for deletion."}],description:"Deletes a cache."},{name:"deleteEntry",parameters:[{name:"cacheId",$ref:"CacheId",description:"Id of cache where the entry will be deleted."},{name:"request",type:"string",description:"URL spec of the request."}],description:"Deletes a cache entry."}]},{domain:"DOMStorage",experimental:!0,description:"Query and modify DOM storage.",types:[{id:"StorageId",type:"object",description:"DOM Storage identifier.",experimental:!0,properties:[{name:"securityOrigin",type:"string",description:"Security origin for the storage."},{name:"isLocalStorage",type:"boolean",description:"Whether the storage is local storage (not session storage)."}]},{id:"Item",type:"array",description:"DOM Storage item.",experimental:!0,items:{type:"string"}}],commands:[{name:"enable",description:"Enables storage tracking, storage events will now be delivered to the client."},{name:"disable",description:"Disables storage tracking, prevents storage events from being sent to the client."},{name:"clear",parameters:[{name:"storageId",$ref:"StorageId"}]},{name:"getDOMStorageItems",parameters:[{name:"storageId",$ref:"StorageId"}],returns:[{name:"entries",type:"array",items:{$ref:"Item"}}]},{name:"setDOMStorageItem",parameters:[{name:"storageId", +$ref:"StorageId"},{name:"key",type:"string"},{name:"value",type:"string"}]},{name:"removeDOMStorageItem",parameters:[{name:"storageId",$ref:"StorageId"},{name:"key",type:"string"}]}],events:[{name:"domStorageItemsCleared",parameters:[{name:"storageId",$ref:"StorageId"}]},{name:"domStorageItemRemoved",parameters:[{name:"storageId",$ref:"StorageId"},{name:"key",type:"string"}]},{name:"domStorageItemAdded",parameters:[{name:"storageId",$ref:"StorageId"},{name:"key",type:"string"},{name:"newValue",type:"string"}]},{name:"domStorageItemUpdated",parameters:[{name:"storageId",$ref:"StorageId"},{name:"key",type:"string"},{name:"oldValue",type:"string"},{name:"newValue",type:"string"}]}]},{domain:"ApplicationCache",experimental:!0,types:[{id:"ApplicationCacheResource",type:"object",description:"Detailed application cache resource information.",properties:[{name:"url",type:"string",description:"Resource url."},{name:"size",type:"integer",description:"Resource size."},{name:"type",type:"string",description:"Resource type."}]},{id:"ApplicationCache",type:"object",description:"Detailed application cache information.",properties:[{name:"manifestURL",type:"string",description:"Manifest URL."},{name:"size",type:"number",description:"Application cache size."},{name:"creationTime",type:"number",description:"Application cache creation time."},{name:"updateTime",type:"number",description:"Application cache update time."},{name:"resources",type:"array",items:{$ref:"ApplicationCacheResource"},description:"Application cache resources."}]},{id:"FrameWithManifest",type:"object",description:"Frame identifier - manifest URL pair.",properties:[{name:"frameId",$ref:"Page.FrameId",description:"Frame identifier."},{name:"manifestURL",type:"string",description:"Manifest URL."},{name:"status",type:"integer",description:"Application cache status."}]}],commands:[{name:"getFramesWithManifests",returns:[{name:"frameIds",type:"array",items:{$ref:"FrameWithManifest"},description:"Array of frame identifiers with manifest urls for each frame containing a document associated with some application cache."}],description:"Returns array of frame identifiers with manifest urls for each frame containing a document associated with some application cache."},{name:"enable",description:"Enables application cache domain notifications."},{name:"getManifestForFrame",parameters:[{name:"frameId",$ref:"Page.FrameId",description:"Identifier of the frame containing document whose manifest is retrieved."}],returns:[{name:"manifestURL",type:"string",description:"Manifest URL for document in the given frame."}],description:"Returns manifest URL for document in the given frame."},{name:"getApplicationCacheForFrame",parameters:[{name:"frameId",$ref:"Page.FrameId",description:"Identifier of the frame containing document whose application cache is retrieved."}],returns:[{name:"applicationCache",$ref:"ApplicationCache",description:"Relevant application cache data for the document in given frame."}],description:"Returns relevant application cache data for the document in given frame."}],events:[{name:"applicationCacheStatusUpdated",parameters:[{name:"frameId",$ref:"Page.FrameId",description:"Identifier of the frame containing document whose application cache updated status."},{name:"manifestURL",type:"string",description:"Manifest URL."},{name:"status",type:"integer",description:"Updated application cache status."}]},{name:"networkStateUpdated",parameters:[{name:"isNowOnline",type:"boolean"}]}]},{domain:"DOM",description:"This domain exposes DOM read/write operations. Each DOM Node is represented with its mirror object that has an id. This id can be used to get additional information on the Node, resolve it into the JavaScript object wrapper, etc. It is important that client receives DOM events only for the nodes that are known to the client. Backend keeps track of the nodes that were sent to the client and never sends the same node twice. It is client's responsibility to collect information about the nodes that were sent to the client.

Note that iframe owner elements will return corresponding document elements as their child nodes.

",dependencies:["Runtime"],types:[{id:"NodeId",type:"integer",description:"Unique DOM node identifier."},{id:"BackendNodeId",type:"integer",description:"Unique DOM node identifier used to reference a node that may not have been pushed to the front-end.",experimental:!0},{id:"BackendNode",type:"object",properties:[{name:"nodeType",type:"integer",description:"Node's nodeType."},{name:"nodeName",type:"string",description:"Node's nodeName."},{name:"backendNodeId",$ref:"BackendNodeId"}],experimental:!0,description:"Backend node with a friendly name."},{id:"PseudoType",type:"string",enum:["first-line","first-letter","before","after","backdrop","selection","first-line-inherited","scrollbar","scrollbar-thumb","scrollbar-button","scrollbar-track","scrollbar-track-piece","scrollbar-corner","resizer","input-list-button"],description:"Pseudo element type."},{id:"ShadowRootType",type:"string",enum:["user-agent","open","closed"],description:"Shadow root type."},{id:"Node",type:"object",properties:[{name:"nodeId",$ref:"NodeId",description:"Node identifier that is passed into the rest of the DOM messages as the nodeId. Backend will only push node with given id once. It is aware of all requested nodes and will only fire DOM events for nodes known to the client."},{name:"parentId",$ref:"NodeId",optional:!0,description:"The id of the parent node if any.",experimental:!0},{name:"backendNodeId",$ref:"BackendNodeId",description:"The BackendNodeId for this node.",experimental:!0},{name:"nodeType",type:"integer",description:"Node's nodeType."},{name:"nodeName",type:"string",description:"Node's nodeName."},{name:"localName",type:"string",description:"Node's localName."},{name:"nodeValue",type:"string",description:"Node's nodeValue."},{name:"childNodeCount",type:"integer",optional:!0,description:"Child count for Container nodes."},{name:"children",type:"array",optional:!0,items:{$ref:"Node"},description:"Child nodes of this node when requested with children."},{name:"attributes",type:"array",optional:!0,items:{type:"string"},description:"Attributes of the Element node in the form of flat array [name1, value1, name2, value2]."},{name:"documentURL",type:"string",optional:!0,description:"Document URL that Document or FrameOwner node points to."},{name:"baseURL",type:"string",optional:!0,description:"Base URL that Document or FrameOwner node uses for URL completion.",experimental:!0},{name:"publicId",type:"string",optional:!0,description:"DocumentType's publicId."},{name:"systemId",type:"string",optional:!0,description:"DocumentType's systemId."},{name:"internalSubset",type:"string",optional:!0,description:"DocumentType's internalSubset."},{name:"xmlVersion",type:"string",optional:!0,description:"Document's XML version in case of XML documents."},{name:"name",type:"string",optional:!0,description:"Attr's name."},{name:"value",type:"string",optional:!0,description:"Attr's value."},{name:"pseudoType",$ref:"PseudoType",optional:!0,description:"Pseudo element type for this node."},{name:"shadowRootType",$ref:"ShadowRootType",optional:!0,description:"Shadow root type."},{name:"frameId",$ref:"Page.FrameId",optional:!0,description:"Frame ID for frame owner elements.",experimental:!0},{name:"contentDocument",$ref:"Node",optional:!0,description:"Content document for frame owner elements."},{name:"shadowRoots",type:"array",optional:!0,items:{$ref:"Node"},description:"Shadow root list for given element host.",experimental:!0},{name:"templateContent",$ref:"Node",optional:!0,description:"Content document fragment for template elements.",experimental:!0},{name:"pseudoElements",type:"array",items:{$ref:"Node"},optional:!0,description:"Pseudo elements associated with this node.",experimental:!0},{name:"importedDocument",$ref:"Node",optional:!0,description:"Import document for the HTMLImport links."},{name:"distributedNodes",type:"array",items:{$ref:"BackendNode"},optional:!0,description:"Distributed nodes for given insertion point.",experimental:!0},{name:"isSVG",type:"boolean",optional:!0,description:"Whether the node is SVG.",experimental:!0}],description:"DOM interaction is implemented in terms of mirror objects that represent the actual DOM nodes. DOMNode is a base node mirror type."},{id:"RGBA",type:"object",properties:[{name:"r",type:"integer",description:"The red component, in the [0-255] range."},{name:"g",type:"integer",description:"The green component, in the [0-255] range."},{name:"b",type:"integer",description:"The blue component, in the [0-255] range."},{name:"a",type:"number",optional:!0,description:"The alpha component, in the [0-1] range (default: 1)."}],description:"A structure holding an RGBA color."},{id:"Quad",type:"array",items:{type:"number"},minItems:8,maxItems:8,description:"An array of quad vertices, x immediately followed by y for each point, points clock-wise.",experimental:!0},{id:"BoxModel",type:"object",experimental:!0,properties:[{name:"content",$ref:"Quad",description:"Content box"},{name:"padding",$ref:"Quad",description:"Padding box"},{name:"border",$ref:"Quad",description:"Border box"},{name:"margin",$ref:"Quad",description:"Margin box"},{name:"width",type:"integer",description:"Node width"},{name:"height",type:"integer",description:"Node height"},{name:"shapeOutside",$ref:"ShapeOutsideInfo",optional:!0,description:"Shape outside coordinates"}],description:"Box model."},{id:"ShapeOutsideInfo",type:"object",experimental:!0,properties:[{name:"bounds",$ref:"Quad",description:"Shape bounds"},{name:"shape",type:"array",items:{type:"any"},description:"Shape coordinate details"},{name:"marginShape",type:"array",items:{type:"any"},description:"Margin shape bounds"}],description:"CSS Shape Outside details."},{id:"Rect",type:"object",experimental:!0,properties:[{name:"x",type:"number",description:"X coordinate"},{name:"y",type:"number",description:"Y coordinate"},{name:"width",type:"number",description:"Rectangle width"},{name:"height",type:"number",description:"Rectangle height"}],description:"Rectangle."}],commands:[{name:"enable",description:"Enables DOM agent for the given page."},{name:"disable",description:"Disables DOM agent for the given page."},{name:"getDocument",parameters:[{name:"depth",type:"integer",optional:!0,description:"The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.",experimental:!0},{name:"pierce",type:"boolean",optional:!0,description:"Whether or not iframes and shadow roots should be traversed when returning the subtree (default is false).",experimental:!0}],returns:[{name:"root",$ref:"Node",description:"Resulting node."}],description:"Returns the root DOM node (and optionally the subtree) to the caller."},{name:"getFlattenedDocument",parameters:[{name:"depth",type:"integer",optional:!0,description:"The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.",experimental:!0},{name:"pierce",type:"boolean",optional:!0,description:"Whether or not iframes and shadow roots should be traversed when returning the subtree (default is false).",experimental:!0}],returns:[{name:"nodes",type:"array",items:{$ref:"Node"},description:"Resulting node."}],description:"Returns the root DOM node (and optionally the subtree) to the caller."},{name:"collectClassNamesFromSubtree",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to collect class names."}],returns:[{name:"classNames",type:"array",items:{type:"string"},description:"Class name list."}],description:"Collects class names for the node with given id and all of it's child nodes.",experimental:!0},{name:"requestChildNodes",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to get children for."},{name:"depth",type:"integer",optional:!0,description:"The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.",experimental:!0},{name:"pierce",type:"boolean",optional:!0,description:"Whether or not iframes and shadow roots should be traversed when returning the sub-tree (default is false).",experimental:!0}],description:"Requests that children of the node with given id are returned to the caller in form of setChildNodes events where not only immediate children are retrieved, but all children down to the specified depth."},{name:"querySelector",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to query upon."},{name:"selector",type:"string",description:"Selector string."}],returns:[{name:"nodeId",$ref:"NodeId",description:"Query selector result."}],description:"Executes querySelector on a given node."},{name:"querySelectorAll",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to query upon."},{name:"selector",type:"string",description:"Selector string."}],returns:[{name:"nodeIds",type:"array",items:{$ref:"NodeId"},description:"Query selector result."}],description:"Executes querySelectorAll on a given node."},{name:"setNodeName",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to set name for."},{name:"name",type:"string",description:"New node's name."}],returns:[{name:"nodeId",$ref:"NodeId",description:"New node's id."}],description:"Sets node name for a node with given id."},{name:"setNodeValue",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to set value for."},{name:"value",type:"string",description:"New node's value."}],description:"Sets node value for a node with given id."},{name:"removeNode",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to remove."}],description:"Removes node with given id."},{name:"setAttributeValue",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the element to set attribute for."},{name:"name",type:"string",description:"Attribute name."},{name:"value",type:"string",description:"Attribute value."}],description:"Sets attribute for an element with given id."},{name:"setAttributesAsText",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the element to set attributes for."},{name:"text",type:"string",description:"Text with a number of attributes. Will parse this text using HTML parser."},{name:"name",type:"string",optional:!0,description:"Attribute name to replace with new attributes derived from text in case text parsed successfully."}],description:"Sets attributes on element with given id. This method is useful when user edits some existing attribute value and types in several attribute name/value pairs."},{name:"removeAttribute",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the element to remove attribute from."},{name:"name",type:"string",description:"Name of the attribute to remove."}],description:"Removes attribute with given name from an element with given id."},{name:"getOuterHTML",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to get markup for."}],returns:[{name:"outerHTML",type:"string",description:"Outer HTML markup."}],description:"Returns node's HTML markup."},{name:"setOuterHTML",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to set markup for."},{name:"outerHTML",type:"string",description:"Outer HTML markup to set."}],description:"Sets node HTML markup, returns new node id."},{name:"performSearch",parameters:[{name:"query",type:"string",description:"Plain text or query selector or XPath search query."},{name:"includeUserAgentShadowDOM",type:"boolean",optional:!0,description:"True to search in user agent shadow DOM.",experimental:!0}],returns:[{name:"searchId",type:"string",description:"Unique search session identifier."},{name:"resultCount",type:"integer",description:"Number of search results."}],description:"Searches for a given string in the DOM tree. Use getSearchResults to access search results or cancelSearch to end this search session.",experimental:!0},{name:"getSearchResults",parameters:[{name:"searchId",type:"string",description:"Unique search session identifier."},{name:"fromIndex",type:"integer",description:"Start index of the search result to be returned."},{name:"toIndex",type:"integer",description:"End index of the search result to be returned."}],returns:[{name:"nodeIds",type:"array",items:{$ref:"NodeId"},description:"Ids of the search result nodes."}],description:"Returns search results from given fromIndex to given toIndex from the sarch with the given identifier.",experimental:!0},{name:"discardSearchResults",parameters:[{name:"searchId",type:"string",description:"Unique search session identifier."}],description:"Discards search results from the session with the given id. getSearchResults should no longer be called for that search.",experimental:!0},{name:"requestNode",parameters:[{name:"objectId",$ref:"Runtime.RemoteObjectId",description:"JavaScript object id to convert into node."}],returns:[{name:"nodeId",$ref:"NodeId",description:"Node id for given object."}],description:"Requests that the node is sent to the caller given the JavaScript node object reference. All nodes that form the path from the node to the root are also sent to the client as a series of setChildNodes notifications."},{name:"highlightRect",description:"Highlights given rectangle.",redirect:"Overlay"},{name:"highlightNode",description:"Highlights DOM node.",redirect:"Overlay"},{name:"hideHighlight",description:"Hides any highlight.",redirect:"Overlay"},{name:"pushNodeByPathToFrontend",parameters:[{name:"path",type:"string",description:"Path to node in the proprietary format."}],returns:[{name:"nodeId",$ref:"NodeId",description:"Id of the node for given path."}],description:"Requests that the node is sent to the caller given its path. // FIXME, use XPath",experimental:!0},{name:"pushNodesByBackendIdsToFrontend",parameters:[{name:"backendNodeIds",type:"array",items:{$ref:"BackendNodeId"},description:"The array of backend node ids."}],returns:[{name:"nodeIds",type:"array",items:{$ref:"NodeId"},description:"The array of ids of pushed nodes that correspond to the backend ids specified in backendNodeIds."}],description:"Requests that a batch of nodes is sent to the caller given their backend node ids.",experimental:!0},{name:"setInspectedNode",parameters:[{name:"nodeId",$ref:"NodeId",description:"DOM node id to be accessible by means of $x command line API."}],description:"Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions).",experimental:!0},{name:"resolveNode",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to resolve."},{name:"objectGroup",type:"string",optional:!0,description:"Symbolic group name that can be used to release multiple objects."}],returns:[{name:"object",$ref:"Runtime.RemoteObject",description:"JavaScript object wrapper for given node."}],description:"Resolves JavaScript node object for given node id."},{name:"getAttributes",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to retrieve attibutes for."}],returns:[{name:"attributes",type:"array",items:{type:"string"},description:"An interleaved array of node attribute names and values."}],description:"Returns attributes for the specified node."},{name:"copyTo",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to copy."},{name:"targetNodeId",$ref:"NodeId",description:"Id of the element to drop the copy into."},{name:"insertBeforeNodeId",$ref:"NodeId",optional:!0,description:"Drop the copy before this node (if absent, the copy becomes the last child of targetNodeId)."}],returns:[{name:"nodeId",$ref:"NodeId",description:"Id of the node clone."}],description:"Creates a deep copy of the specified node and places it into the target container before the given anchor.",experimental:!0},{name:"moveTo",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to move."},{name:"targetNodeId",$ref:"NodeId",description:"Id of the element to drop the moved node into."},{name:"insertBeforeNodeId",$ref:"NodeId",optional:!0,description:"Drop node before this one (if absent, the moved node becomes the last child of targetNodeId)."}],returns:[{name:"nodeId",$ref:"NodeId",description:"New id of the moved node."}],description:"Moves node into the new container, places it before the given anchor."},{name:"undo",description:"Undoes the last performed action.",experimental:!0},{name:"redo",description:"Re-does the last undone action.",experimental:!0},{name:"markUndoableState",description:"Marks last undoable state.",experimental:!0},{name:"focus",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to focus."}],description:"Focuses the given element.",experimental:!0},{name:"setFileInputFiles",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the file input node to set files for."},{name:"files",type:"array",items:{type:"string"},description:"Array of file paths to set."}],description:"Sets files for the given file input element.",experimental:!0},{name:"getBoxModel",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node to get box model for."}],returns:[{name:"model",$ref:"BoxModel",description:"Box model for the node."}],description:"Returns boxes for the currently selected nodes.",experimental:!0},{name:"getNodeForLocation",parameters:[{name:"x",type:"integer",description:"X coordinate."},{name:"y",type:"integer",description:"Y coordinate."},{name:"includeUserAgentShadowDOM",type:"boolean",optional:!0,description:"False to skip to the nearest non-UA shadow root ancestor (default: false)."}],returns:[{name:"nodeId",$ref:"NodeId",description:"Id of the node at given coordinates."}],description:"Returns node id at given location.",experimental:!0},{name:"getRelayoutBoundary",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node."}],returns:[{name:"nodeId",$ref:"NodeId",description:"Relayout boundary node id for the given node."}],description:"Returns the id of the nearest ancestor that is a relayout boundary.",experimental:!0}],events:[{name:"documentUpdated",description:"Fired when Document has been totally updated. Node ids are no longer valid."},{name:"setChildNodes",parameters:[{name:"parentId",$ref:"NodeId",description:"Parent node id to populate with children."},{name:"nodes",type:"array",items:{$ref:"Node"},description:"Child nodes array."}],description:"Fired when backend wants to provide client with the missing DOM structure. This happens upon most of the calls requesting node ids."},{name:"attributeModified",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node that has changed."},{name:"name",type:"string",description:"Attribute name."},{name:"value",type:"string",description:"Attribute value."}],description:"Fired when Element's attribute is modified."},{name:"attributeRemoved",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node that has changed."},{name:"name",type:"string",description:"A ttribute name."}],description:"Fired when Element's attribute is removed."},{name:"inlineStyleInvalidated",parameters:[{name:"nodeIds",type:"array",items:{$ref:"NodeId"},description:"Ids of the nodes for which the inline styles have been invalidated."}],description:"Fired when Element's inline style is modified via a CSS property modification.",experimental:!0},{name:"characterDataModified",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node that has changed."},{name:"characterData",type:"string",description:"New text value."}],description:"Mirrors DOMCharacterDataModified event."},{name:"childNodeCountUpdated",parameters:[{name:"nodeId",$ref:"NodeId",description:"Id of the node that has changed."},{name:"childNodeCount",type:"integer",description:"New node count."}],description:"Fired when Container's child node count has changed."},{name:"childNodeInserted",parameters:[{name:"parentNodeId",$ref:"NodeId",description:"Id of the node that has changed."},{name:"previousNodeId",$ref:"NodeId",description:"If of the previous siblint."},{name:"node",$ref:"Node",description:"Inserted node data."}],description:"Mirrors DOMNodeInserted event."},{name:"childNodeRemoved",parameters:[{name:"parentNodeId",$ref:"NodeId",description:"Parent id."},{name:"nodeId",$ref:"NodeId",description:"Id of the node that has been removed."}],description:"Mirrors DOMNodeRemoved event."},{name:"shadowRootPushed",parameters:[{name:"hostId",$ref:"NodeId",description:"Host element id."},{name:"root",$ref:"Node",description:"Shadow root."}],description:"Called when shadow root is pushed into the element.",experimental:!0},{name:"shadowRootPopped",parameters:[{name:"hostId",$ref:"NodeId",description:"Host element id."},{name:"rootId",$ref:"NodeId",description:"Shadow root id."}],description:"Called when shadow root is popped from the element.",experimental:!0},{name:"pseudoElementAdded",parameters:[{name:"parentId",$ref:"NodeId",description:"Pseudo element's parent element id."},{name:"pseudoElement",$ref:"Node",description:"The added pseudo element."}],description:"Called when a pseudo element is added to an element.",experimental:!0},{name:"pseudoElementRemoved",parameters:[{name:"parentId",$ref:"NodeId",description:"Pseudo element's parent element id."},{name:"pseudoElementId",$ref:"NodeId",description:"The removed pseudo element id."}],description:"Called when a pseudo element is removed from an element.",experimental:!0},{name:"distributedNodesUpdated",parameters:[{name:"insertionPointId",$ref:"NodeId",description:"Insertion point where distrubuted nodes were updated."},{name:"distributedNodes",type:"array",items:{$ref:"BackendNode"},description:"Distributed nodes for given insertion point."}],description:"Called when distrubution is changed.",experimental:!0}]},{domain:"CSS",experimental:!0,description:"This domain exposes CSS read/write operations. All CSS objects (stylesheets, rules, and styles) have an associated id used in subsequent operations on the related object. Each object type has a specific id structure, and those are not interchangeable between objects of different kinds. CSS objects can be loaded using the get*ForNode() calls (which accept a DOM node id). A client can also discover all the existing stylesheets with the getAllStyleSheets() method (or keeping track of the styleSheetAdded/styleSheetRemoved events) and subsequently load the required stylesheet contents using the getStyleSheet[Text]() methods.",dependencies:["DOM"],types:[{id:"StyleSheetId",type:"string"},{id:"StyleSheetOrigin",type:"string",enum:["injected","user-agent","inspector","regular"],description:'Stylesheet type: "injected" for stylesheets injected via extension, "user-agent" for user-agent stylesheets, "inspector" for stylesheets created by the inspector (i.e. those holding the "via inspector" rules), "regular" for regular stylesheets.'},{id:"PseudoElementMatches",type:"object",properties:[{name:"pseudoType",$ref:"DOM.PseudoType",description:"Pseudo element type."},{name:"matches",type:"array",items:{$ref:"RuleMatch"},description:"Matches of CSS rules applicable to the pseudo style."}],description:"CSS rule collection for a single pseudo style."},{id:"InheritedStyleEntry",type:"object",properties:[{name:"inlineStyle",$ref:"CSSStyle",optional:!0,description:"The ancestor node's inline style, if any, in the style inheritance chain."},{name:"matchedCSSRules",type:"array",items:{$ref:"RuleMatch"},description:"Matches of CSS rules matching the ancestor node in the style inheritance chain."}],description:"Inherited CSS rule collection from ancestor node."},{id:"RuleMatch",type:"object",properties:[{name:"rule",$ref:"CSSRule",description:"CSS rule in the match."},{name:"matchingSelectors",type:"array",items:{type:"integer"},description:"Matching selector indices in the rule's selectorList selectors (0-based)."}],description:"Match data for a CSS rule."},{id:"Value",type:"object",properties:[{name:"text",type:"string",description:"Value text."},{name:"range",$ref:"SourceRange",optional:!0,description:"Value range in the underlying resource (if available)."}],description:"Data for a simple selector (these are delimited by commas in a selector list)."},{id:"SelectorList",type:"object",properties:[{name:"selectors",type:"array",items:{$ref:"Value"},description:"Selectors in the list."},{name:"text",type:"string",description:"Rule selector text."}],description:"Selector list data."},{id:"CSSStyleSheetHeader",type:"object",properties:[{name:"styleSheetId",$ref:"StyleSheetId",description:"The stylesheet identifier."},{name:"frameId",$ref:"Page.FrameId",description:"Owner frame identifier."},{name:"sourceURL",type:"string",description:"Stylesheet resource URL."},{name:"sourceMapURL",type:"string",optional:!0,description:"URL of source map associated with the stylesheet (if any)."},{name:"origin",$ref:"StyleSheetOrigin",description:"Stylesheet origin."},{name:"title",type:"string",description:"Stylesheet title."},{name:"ownerNode",$ref:"DOM.BackendNodeId",optional:!0,description:"The backend id for the owner node of the stylesheet."},{name:"disabled",type:"boolean",description:"Denotes whether the stylesheet is disabled."},{name:"hasSourceURL",type:"boolean",optional:!0,description:"Whether the sourceURL field value comes from the sourceURL comment."},{name:"isInline",type:"boolean",description:"Whether this stylesheet is created for STYLE tag by parser. This flag is not set for document.written STYLE tags."},{name:"startLine",type:"number",description:"Line offset of the stylesheet within the resource (zero based)."},{name:"startColumn",type:"number",description:"Column offset of the stylesheet within the resource (zero based)."},{name:"length",type:"number",description:"Size of the content (in characters).",experimental:!0}],description:"CSS stylesheet metainformation."},{id:"CSSRule",type:"object",properties:[{name:"styleSheetId",$ref:"StyleSheetId",optional:!0,description:"The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from."},{name:"selectorList",$ref:"SelectorList",description:"Rule selector data."},{name:"origin",$ref:"StyleSheetOrigin",description:"Parent stylesheet's origin."},{name:"style",$ref:"CSSStyle",description:"Associated style declaration."},{name:"media",type:"array",items:{$ref:"CSSMedia"},optional:!0,description:"Media list array (for rules involving media queries). The array enumerates media queries starting with the innermost one, going outwards."}],description:"CSS rule representation."},{id:"RuleUsage",type:"object",properties:[{name:"styleSheetId",$ref:"StyleSheetId",description:"The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from."},{name:"startOffset",type:"number",description:"Offset of the start of the rule (including selector) from the beginning of the stylesheet."},{name:"endOffset",type:"number",description:"Offset of the end of the rule body from the beginning of the stylesheet."},{name:"used",type:"boolean",description:"Indicates whether the rule was actually used by some element in the page."}],description:"CSS coverage information.",experimental:!0},{id:"SourceRange",type:"object", +properties:[{name:"startLine",type:"integer",description:"Start line of range."},{name:"startColumn",type:"integer",description:"Start column of range (inclusive)."},{name:"endLine",type:"integer",description:"End line of range"},{name:"endColumn",type:"integer",description:"End column of range (exclusive)."}],description:"Text range within a resource. All numbers are zero-based."},{id:"ShorthandEntry",type:"object",properties:[{name:"name",type:"string",description:"Shorthand name."},{name:"value",type:"string",description:"Shorthand value."},{name:"important",type:"boolean",optional:!0,description:'Whether the property has "!important" annotation (implies false if absent).'}]},{id:"CSSComputedStyleProperty",type:"object",properties:[{name:"name",type:"string",description:"Computed style property name."},{name:"value",type:"string",description:"Computed style property value."}]},{id:"CSSStyle",type:"object",properties:[{name:"styleSheetId",$ref:"StyleSheetId",optional:!0,description:"The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from."},{name:"cssProperties",type:"array",items:{$ref:"CSSProperty"},description:"CSS properties in the style."},{name:"shorthandEntries",type:"array",items:{$ref:"ShorthandEntry"},description:"Computed values for all shorthands found in the style."},{name:"cssText",type:"string",optional:!0,description:"Style declaration text (if available)."},{name:"range",$ref:"SourceRange",optional:!0,description:"Style declaration range in the enclosing stylesheet (if available)."}],description:"CSS style representation."},{id:"CSSProperty",type:"object",properties:[{name:"name",type:"string",description:"The property name."},{name:"value",type:"string",description:"The property value."},{name:"important",type:"boolean",optional:!0,description:'Whether the property has "!important" annotation (implies false if absent).'},{name:"implicit",type:"boolean",optional:!0,description:"Whether the property is implicit (implies false if absent)."},{name:"text",type:"string",optional:!0,description:"The full property text as specified in the style."},{name:"parsedOk",type:"boolean",optional:!0,description:"Whether the property is understood by the browser (implies true if absent)."},{name:"disabled",type:"boolean",optional:!0,description:"Whether the property is disabled by the user (present for source-based properties only)."},{name:"range",$ref:"SourceRange",optional:!0,description:"The entire property range in the enclosing style declaration (if available)."}],description:"CSS property declaration data."},{id:"CSSMedia",type:"object",properties:[{name:"text",type:"string",description:"Media query text."},{name:"source",type:"string",enum:["mediaRule","importRule","linkedSheet","inlineSheet"],description:'Source of the media query: "mediaRule" if specified by a @media rule, "importRule" if specified by an @import rule, "linkedSheet" if specified by a "media" attribute in a linked stylesheet\'s LINK tag, "inlineSheet" if specified by a "media" attribute in an inline stylesheet\'s STYLE tag.'},{name:"sourceURL",type:"string",optional:!0,description:"URL of the document containing the media query description."},{name:"range",$ref:"SourceRange",optional:!0,description:"The associated rule (@media or @import) header range in the enclosing stylesheet (if available)."},{name:"styleSheetId",$ref:"StyleSheetId",optional:!0,description:"Identifier of the stylesheet containing this object (if exists)."},{name:"mediaList",type:"array",items:{$ref:"MediaQuery"},optional:!0,experimental:!0,description:"Array of media queries."}],description:"CSS media rule descriptor."},{id:"MediaQuery",type:"object",properties:[{name:"expressions",type:"array",items:{$ref:"MediaQueryExpression"},description:"Array of media query expressions."},{name:"active",type:"boolean",description:"Whether the media query condition is satisfied."}],description:"Media query descriptor.",experimental:!0},{id:"MediaQueryExpression",type:"object",properties:[{name:"value",type:"number",description:"Media query expression value."},{name:"unit",type:"string",description:"Media query expression units."},{name:"feature",type:"string",description:"Media query expression feature."},{name:"valueRange",$ref:"SourceRange",optional:!0,description:"The associated range of the value text in the enclosing stylesheet (if available)."},{name:"computedLength",type:"number",optional:!0,description:"Computed length of media query expression (if applicable)."}],description:"Media query expression descriptor.",experimental:!0},{id:"PlatformFontUsage",type:"object",properties:[{name:"familyName",type:"string",description:"Font's family name reported by platform."},{name:"isCustomFont",type:"boolean",description:"Indicates if the font was downloaded or resolved locally."},{name:"glyphCount",type:"number",description:"Amount of glyphs that were rendered with this font."}],description:"Information about amount of glyphs that were rendered with given font.",experimental:!0},{id:"CSSKeyframesRule",type:"object",properties:[{name:"animationName",$ref:"Value",description:"Animation name."},{name:"keyframes",type:"array",items:{$ref:"CSSKeyframeRule"},description:"List of keyframes."}],description:"CSS keyframes rule representation."},{id:"CSSKeyframeRule",type:"object",properties:[{name:"styleSheetId",$ref:"StyleSheetId",optional:!0,description:"The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from."},{name:"origin",$ref:"StyleSheetOrigin",description:"Parent stylesheet's origin."},{name:"keyText",$ref:"Value",description:"Associated key text."},{name:"style",$ref:"CSSStyle",description:"Associated style declaration."}],description:"CSS keyframe rule representation."},{id:"StyleDeclarationEdit",type:"object",properties:[{name:"styleSheetId",$ref:"StyleSheetId",description:"The css style sheet identifier."},{name:"range",$ref:"SourceRange",description:"The range of the style text in the enclosing stylesheet."},{name:"text",type:"string",description:"New style text."}],description:"A descriptor of operation to mutate style declaration text."},{id:"InlineTextBox",type:"object",properties:[{name:"boundingBox",$ref:"DOM.Rect",description:"The absolute position bounding box."},{name:"startCharacterIndex",type:"integer",description:"The starting index in characters, for this post layout textbox substring."},{name:"numCharacters",type:"integer",description:"The number of characters in this post layout textbox substring."}],description:"Details of post layout rendered text positions. The exact layout should not be regarded as stable and may change between versions.",experimental:!0},{id:"LayoutTreeNode",type:"object",properties:[{name:"nodeId",$ref:"DOM.NodeId",description:"The id of the related DOM node matching one from DOM.GetDocument."},{name:"boundingBox",$ref:"DOM.Rect",description:"The absolute position bounding box."},{name:"layoutText",type:"string",optional:!0,description:"Contents of the LayoutText if any"},{name:"inlineTextNodes",type:"array",optional:!0,items:{$ref:"InlineTextBox"},description:"The post layout inline text nodes, if any."},{name:"styleIndex",type:"integer",optional:!0,description:"Index into the computedStyles array returned by getLayoutTreeAndStyles."}],description:"Details of an element in the DOM tree with a LayoutObject.",experimental:!0},{id:"ComputedStyle",type:"object",properties:[{name:"properties",type:"array",items:{$ref:"CSSComputedStyleProperty"}}],description:"A subset of the full ComputedStyle as defined by the request whitelist.",experimental:!0}],commands:[{name:"enable",description:"Enables the CSS agent for the given page. Clients should not assume that the CSS agent has been enabled until the result of this command is received."},{name:"disable",description:"Disables the CSS agent for the given page."},{name:"getMatchedStylesForNode",parameters:[{name:"nodeId",$ref:"DOM.NodeId"}],returns:[{name:"inlineStyle",$ref:"CSSStyle",optional:!0,description:"Inline style for the specified DOM node."},{name:"attributesStyle",$ref:"CSSStyle",optional:!0,description:'Attribute-defined element style (e.g. resulting from "width=20 height=100%").'},{name:"matchedCSSRules",type:"array",items:{$ref:"RuleMatch"},optional:!0,description:"CSS rules matching this node, from all applicable stylesheets."},{name:"pseudoElements",type:"array",items:{$ref:"PseudoElementMatches"},optional:!0,description:"Pseudo style matches for this node."},{name:"inherited",type:"array",items:{$ref:"InheritedStyleEntry"},optional:!0,description:"A chain of inherited styles (from the immediate node parent up to the DOM tree root)."},{name:"cssKeyframesRules",type:"array",items:{$ref:"CSSKeyframesRule"},optional:!0,description:"A list of CSS keyframed animations matching this node."}],description:"Returns requested styles for a DOM node identified by nodeId."},{name:"getInlineStylesForNode",parameters:[{name:"nodeId",$ref:"DOM.NodeId"}],returns:[{name:"inlineStyle",$ref:"CSSStyle",optional:!0,description:"Inline style for the specified DOM node."},{name:"attributesStyle",$ref:"CSSStyle",optional:!0,description:'Attribute-defined element style (e.g. resulting from "width=20 height=100%").'}],description:'Returns the styles defined inline (explicitly in the "style" attribute and implicitly, using DOM attributes) for a DOM node identified by nodeId.'},{name:"getComputedStyleForNode",parameters:[{name:"nodeId",$ref:"DOM.NodeId"}],returns:[{name:"computedStyle",type:"array",items:{$ref:"CSSComputedStyleProperty"},description:"Computed style for the specified DOM node."}],description:"Returns the computed style for a DOM node identified by nodeId."},{name:"getPlatformFontsForNode",parameters:[{name:"nodeId",$ref:"DOM.NodeId"}],returns:[{name:"fonts",type:"array",items:{$ref:"PlatformFontUsage"},description:"Usage statistics for every employed platform font."}],description:"Requests information about platform fonts which we used to render child TextNodes in the given node.",experimental:!0},{name:"getStyleSheetText",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"}],returns:[{name:"text",type:"string",description:"The stylesheet text."}],description:"Returns the current textual content and the URL for a stylesheet."},{name:"collectClassNames",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"}],returns:[{name:"classNames",type:"array",items:{type:"string"},description:"Class name list."}],description:"Returns all class names from specified stylesheet.",experimental:!0},{name:"setStyleSheetText",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"},{name:"text",type:"string"}],returns:[{name:"sourceMapURL",type:"string",optional:!0,description:"URL of source map associated with script (if any)."}],description:"Sets the new stylesheet text."},{name:"setRuleSelector",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"},{name:"range",$ref:"SourceRange"},{name:"selector",type:"string"}],returns:[{name:"selectorList",$ref:"SelectorList",description:"The resulting selector list after modification."}],description:"Modifies the rule selector."},{name:"setKeyframeKey",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"},{name:"range",$ref:"SourceRange"},{name:"keyText",type:"string"}],returns:[{name:"keyText",$ref:"Value",description:"The resulting key text after modification."}],description:"Modifies the keyframe rule key text."},{name:"setStyleTexts",parameters:[{name:"edits",type:"array",items:{$ref:"StyleDeclarationEdit"}}],returns:[{name:"styles",type:"array",items:{$ref:"CSSStyle"},description:"The resulting styles after modification."}],description:"Applies specified style edits one after another in the given order."},{name:"setMediaText",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"},{name:"range",$ref:"SourceRange"},{name:"text",type:"string"}],returns:[{name:"media",$ref:"CSSMedia",description:"The resulting CSS media rule after modification."}],description:"Modifies the rule selector."},{name:"createStyleSheet",parameters:[{name:"frameId",$ref:"Page.FrameId",description:'Identifier of the frame where "via-inspector" stylesheet should be created.'}],returns:[{name:"styleSheetId",$ref:"StyleSheetId",description:'Identifier of the created "via-inspector" stylesheet.'}],description:'Creates a new special "via-inspector" stylesheet in the frame with given frameId.'},{name:"addRule",parameters:[{name:"styleSheetId",$ref:"StyleSheetId",description:"The css style sheet identifier where a new rule should be inserted."},{name:"ruleText",type:"string",description:"The text of a new rule."},{name:"location",$ref:"SourceRange",description:"Text position of a new rule in the target style sheet."}],returns:[{name:"rule",$ref:"CSSRule",description:"The newly created rule."}],description:"Inserts a new rule with the given ruleText in a stylesheet with given styleSheetId, at the position specified by location."},{name:"forcePseudoState",parameters:[{name:"nodeId",$ref:"DOM.NodeId",description:"The element id for which to force the pseudo state."},{name:"forcedPseudoClasses",type:"array",items:{type:"string",enum:["active","focus","hover","visited"]},description:"Element pseudo classes to force when computing the element's style."}],description:"Ensures that the given node will have specified pseudo-classes whenever its style is computed by the browser."},{name:"getMediaQueries",returns:[{name:"medias",type:"array",items:{$ref:"CSSMedia"}}],description:"Returns all media queries parsed by the rendering engine.",experimental:!0},{name:"setEffectivePropertyValueForNode",parameters:[{name:"nodeId",$ref:"DOM.NodeId",description:"The element id for which to set property."},{name:"propertyName",type:"string"},{name:"value",type:"string"}],description:"Find a rule with the given active property for the given node and set the new value for this property",experimental:!0},{name:"getBackgroundColors",parameters:[{name:"nodeId",$ref:"DOM.NodeId",description:"Id of the node to get background colors for."}],returns:[{name:"backgroundColors",type:"array",items:{type:"string"},description:"The range of background colors behind this element, if it contains any visible text. If no visible text is present, this will be undefined. In the case of a flat background color, this will consist of simply that color. In the case of a gradient, this will consist of each of the color stops. For anything more complicated, this will be an empty array. Images will be ignored (as if the image had failed to load).",optional:!0}],experimental:!0},{name:"getLayoutTreeAndStyles",parameters:[{name:"computedStyleWhitelist",type:"array",items:{type:"string"},description:"Whitelist of computed styles to return."}],returns:[{name:"layoutTreeNodes",type:"array",items:{$ref:"LayoutTreeNode"}},{name:"computedStyles",type:"array",items:{$ref:"ComputedStyle"}}],description:"For the main document and any content documents, return the LayoutTreeNodes and a whitelisted subset of the computed style. It only returns pushed nodes, on way to pull all nodes is to call DOM.getDocument with a depth of -1.",experimental:!0},{name:"startRuleUsageTracking",description:"Enables the selector recording.",experimental:!0},{name:"takeCoverageDelta",description:"Obtain list of rules that became used since last call to this method (or since start of coverage instrumentation)",returns:[{name:"coverage",type:"array",items:{$ref:"RuleUsage"}}],experimental:!0},{name:"stopRuleUsageTracking",returns:[{name:"ruleUsage",type:"array",items:{$ref:"RuleUsage"}}],description:"The list of rules with an indication of whether these were used",experimental:!0}],events:[{name:"mediaQueryResultChanged",description:"Fires whenever a MediaQuery result changes (for example, after a browser window has been resized.) The current implementation considers only viewport-dependent media features."},{name:"fontsUpdated",description:"Fires whenever a web font gets loaded."},{name:"styleSheetChanged",parameters:[{name:"styleSheetId",$ref:"StyleSheetId"}],description:"Fired whenever a stylesheet is changed as a result of the client operation."},{name:"styleSheetAdded",parameters:[{name:"header",$ref:"CSSStyleSheetHeader",description:"Added stylesheet metainfo."}],description:"Fired whenever an active document stylesheet is added."},{name:"styleSheetRemoved",parameters:[{name:"styleSheetId",$ref:"StyleSheetId",description:"Identifier of the removed stylesheet."}],description:"Fired whenever an active document stylesheet is removed."}]},{domain:"IO",description:"Input/Output operations for streams produced by DevTools.",experimental:!0,types:[{id:"StreamHandle",type:"string"}],commands:[{name:"read",description:"Read a chunk of the stream",parameters:[{name:"handle",$ref:"StreamHandle",description:"Handle of the stream to read."},{name:"offset",type:"integer",optional:!0,description:"Seek to the specified offset before reading (if not specificed, proceed with offset following the last read)."},{name:"size",type:"integer",optional:!0,description:"Maximum number of bytes to read (left upon the agent discretion if not specified)."}],returns:[{name:"data",type:"string",description:"Data that were read."},{name:"eof",type:"boolean",description:"Set if the end-of-file condition occured while reading."}]},{name:"close",description:"Close the stream, discard any temporary backing storage.",parameters:[{name:"handle",$ref:"StreamHandle",description:"Handle of the stream to close."}]}]},{domain:"DOMDebugger",description:"DOM debugging allows setting breakpoints on particular DOM operations and events. JavaScript execution will stop on these operations as if there was a regular breakpoint set.",dependencies:["DOM","Debugger"],types:[{id:"DOMBreakpointType",type:"string",enum:["subtree-modified","attribute-modified","node-removed"],description:"DOM breakpoint type."},{id:"EventListener",type:"object",description:"Object event listener.",properties:[{name:"type",type:"string",description:"EventListener's type."},{name:"useCapture",type:"boolean",description:"EventListener's useCapture."},{name:"passive",type:"boolean",description:"EventListener's passive flag."},{name:"once",type:"boolean",description:"EventListener's once flag."},{name:"scriptId",$ref:"Runtime.ScriptId",description:"Script id of the handler code."},{name:"lineNumber",type:"integer",description:"Line number in the script (0-based)."},{name:"columnNumber",type:"integer",description:"Column number in the script (0-based)."},{name:"handler",$ref:"Runtime.RemoteObject",optional:!0,description:"Event handler function value."},{name:"originalHandler",$ref:"Runtime.RemoteObject",optional:!0,description:"Event original handler function value."},{name:"backendNodeId",$ref:"DOM.BackendNodeId",optional:!0,description:"Node the listener is added to (if any)."}],experimental:!0}],commands:[{name:"setDOMBreakpoint",parameters:[{name:"nodeId",$ref:"DOM.NodeId",description:"Identifier of the node to set breakpoint on."},{name:"type",$ref:"DOMBreakpointType",description:"Type of the operation to stop upon."}],description:"Sets breakpoint on particular operation with DOM."},{name:"removeDOMBreakpoint",parameters:[{name:"nodeId",$ref:"DOM.NodeId",description:"Identifier of the node to remove breakpoint from."},{name:"type",$ref:"DOMBreakpointType",description:"Type of the breakpoint to remove."}],description:"Removes DOM breakpoint that was set using setDOMBreakpoint."},{name:"setEventListenerBreakpoint",parameters:[{name:"eventName",type:"string",description:"DOM Event name to stop on (any DOM event will do)."},{name:"targetName",type:"string",optional:!0,description:'EventTarget interface name to stop on. If equal to "*" or not provided, will stop on any EventTarget.',experimental:!0}],description:"Sets breakpoint on particular DOM event."},{name:"removeEventListenerBreakpoint",parameters:[{name:"eventName",type:"string",description:"Event name."},{name:"targetName",type:"string",optional:!0,description:"EventTarget interface name.",experimental:!0}],description:"Removes breakpoint on particular DOM event."},{name:"setInstrumentationBreakpoint",parameters:[{name:"eventName",type:"string",description:"Instrumentation name to stop on."}],description:"Sets breakpoint on particular native event.",experimental:!0},{name:"removeInstrumentationBreakpoint",parameters:[{name:"eventName",type:"string",description:"Instrumentation name to stop on."}],description:"Removes breakpoint on particular native event.",experimental:!0},{name:"setXHRBreakpoint",parameters:[{name:"url",type:"string",description:"Resource URL substring. All XHRs having this substring in the URL will get stopped upon."}],description:"Sets breakpoint on XMLHttpRequest."},{name:"removeXHRBreakpoint",parameters:[{name:"url",type:"string",description:"Resource URL substring."}],description:"Removes breakpoint from XMLHttpRequest."},{name:"getEventListeners",experimental:!0,parameters:[{name:"objectId",$ref:"Runtime.RemoteObjectId",description:"Identifier of the object to return listeners for."},{name:"depth",type:"integer",optional:!0,description:"The maximum depth at which Node children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.",experimental:!0},{name:"pierce",type:"boolean",optional:!0,description:"Whether or not iframes and shadow roots should be traversed when returning the subtree (default is false). Reports listeners for all contexts if pierce is enabled.",experimental:!0}],returns:[{name:"listeners",type:"array",items:{$ref:"EventListener"},description:"Array of relevant listeners."}],description:"Returns event listeners of the given object."}]},{domain:"Target",description:"Supports additional targets discovery and allows to attach to them.",experimental:!0,types:[{id:"TargetID",type:"string"},{id:"BrowserContextID",type:"string"},{id:"TargetInfo",type:"object",properties:[{name:"targetId",$ref:"TargetID"},{name:"type",type:"string"},{name:"title",type:"string"},{name:"url",type:"string"}]},{id:"RemoteLocation",type:"object",properties:[{name:"host",type:"string"},{name:"port",type:"integer"}]}],commands:[{name:"setDiscoverTargets",description:"Controls whether to discover available targets and notify via targetCreated/targetDestroyed events.",parameters:[{name:"discover",type:"boolean",description:"Whether to discover available targets."}]},{name:"setAutoAttach",description:"Controls whether to automatically attach to new targets which are considered to be related to this one. When turned on, attaches to all existing related targets as well. When turned off, automatically detaches from all currently attached targets.",parameters:[{name:"autoAttach",type:"boolean",description:"Whether to auto-attach to related targets."},{name:"waitForDebuggerOnStart",type:"boolean",description:"Whether to pause new targets when attaching to them. Use Runtime.runIfWaitingForDebugger to run paused targets."}]},{name:"setAttachToFrames",parameters:[{name:"value",type:"boolean",description:"Whether to attach to frames."}]},{name:"setRemoteLocations",description:"Enables target discovery for the specified locations, when setDiscoverTargets was set to true.",parameters:[{name:"locations",type:"array",items:{$ref:"RemoteLocation"},description:"List of remote locations."}]},{name:"sendMessageToTarget",description:"Sends protocol message to the target with given id.",parameters:[{name:"targetId",$ref:"TargetID"},{name:"message",type:"string"}]},{name:"getTargetInfo",description:"Returns information about a target.",parameters:[{name:"targetId",$ref:"TargetID"}],returns:[{name:"targetInfo",$ref:"TargetInfo"}]},{name:"activateTarget",description:"Activates (focuses) the target.",parameters:[{name:"targetId",$ref:"TargetID"}]},{name:"closeTarget",description:"Closes the target. If the target is a page that gets closed too.",parameters:[{name:"targetId",$ref:"TargetID"}],returns:[{name:"success",type:"boolean"}]},{name:"attachToTarget",description:"Attaches to the target with given id.",parameters:[{name:"targetId",$ref:"TargetID"}],returns:[{name:"success",type:"boolean",description:"Whether attach succeeded."}]},{name:"detachFromTarget",description:"Detaches from the target with given id.",parameters:[{name:"targetId",$ref:"TargetID"}]},{name:"createBrowserContext",description:"Creates a new empty BrowserContext. Similar to an incognito profile but you can have more than one.",returns:[{name:"browserContextId",$ref:"BrowserContextID",description:"The id of the context created."}]},{name:"disposeBrowserContext",description:"Deletes a BrowserContext, will fail of any open page uses it.",parameters:[{name:"browserContextId",$ref:"BrowserContextID"}],returns:[{name:"success",type:"boolean"}]},{name:"createTarget",description:"Creates a new page.",parameters:[{name:"url",type:"string",description:"The initial URL the page will be navigated to."},{name:"width",type:"integer",description:"Frame width in DIP (headless chrome only).",optional:!0},{name:"height",type:"integer",description:"Frame height in DIP (headless chrome only).",optional:!0},{name:"browserContextId",$ref:"BrowserContextID",description:"The browser context to create the page in (headless chrome only).",optional:!0}],returns:[{name:"targetId",$ref:"TargetID",description:"The id of the page opened."}]},{name:"getTargets",description:"Retrieves a list of available targets.",returns:[{name:"targetInfos",type:"array",items:{$ref:"TargetInfo"},description:"The list of targets."}]}],events:[{name:"targetCreated",description:"Issued when a possible inspection target is created.",parameters:[{name:"targetInfo",$ref:"TargetInfo"}]},{name:"targetDestroyed",description:"Issued when a target is destroyed.",parameters:[{name:"targetId",$ref:"TargetID"}]},{name:"attachedToTarget",description:"Issued when attached to target because of auto-attach or attachToTarget command.",parameters:[{name:"targetInfo",$ref:"TargetInfo"},{name:"waitingForDebugger",type:"boolean"}]},{name:"detachedFromTarget",description:"Issued when detached from target for any reason (including detachFromTarget command).",parameters:[{name:"targetId",$ref:"TargetID"}]},{name:"receivedMessageFromTarget",description:"Notifies about new protocol message from attached target.",parameters:[{name:"targetId",$ref:"TargetID"},{name:"message",type:"string"}]}]},{domain:"ServiceWorker",experimental:!0,types:[{id:"ServiceWorkerRegistration",type:"object",description:"ServiceWorker registration.",properties:[{name:"registrationId",type:"string"},{name:"scopeURL",type:"string"},{name:"isDeleted",type:"boolean"}]},{id:"ServiceWorkerVersionRunningStatus",type:"string",enum:["stopped","starting","running","stopping"]},{id:"ServiceWorkerVersionStatus",type:"string",enum:["new","installing","installed","activating","activated","redundant"]},{id:"ServiceWorkerVersion",type:"object",description:"ServiceWorker version.",properties:[{name:"versionId",type:"string"},{name:"registrationId",type:"string"},{name:"scriptURL",type:"string"},{name:"runningStatus",$ref:"ServiceWorkerVersionRunningStatus"},{name:"status",$ref:"ServiceWorkerVersionStatus"},{name:"scriptLastModified",type:"number",optional:!0,description:"The Last-Modified header value of the main script."},{name:"scriptResponseTime",type:"number",optional:!0,description:"The time at which the response headers of the main script were received from the server. For cached script it is the last time the cache entry was validated."},{name:"controlledClients",type:"array",optional:!0,items:{$ref:"Target.TargetID"}},{name:"targetId",$ref:"Target.TargetID",optional:!0}]},{id:"ServiceWorkerErrorMessage",type:"object",description:"ServiceWorker error message.",properties:[{name:"errorMessage",type:"string"},{name:"registrationId",type:"string"},{name:"versionId",type:"string"},{name:"sourceURL",type:"string"},{name:"lineNumber",type:"integer"},{name:"columnNumber",type:"integer"}]}],commands:[{name:"enable"},{name:"disable"},{name:"unregister",parameters:[{name:"scopeURL",type:"string"}]},{name:"updateRegistration",parameters:[{name:"scopeURL",type:"string"}]},{name:"startWorker",parameters:[{name:"scopeURL",type:"string"}]},{name:"skipWaiting",parameters:[{name:"scopeURL",type:"string"}]},{name:"stopWorker",parameters:[{name:"versionId",type:"string"}]},{name:"inspectWorker",parameters:[{name:"versionId",type:"string"}]},{name:"setForceUpdateOnPageLoad",parameters:[{name:"forceUpdateOnPageLoad",type:"boolean"}]},{name:"deliverPushMessage",parameters:[{name:"origin",type:"string"},{name:"registrationId",type:"string"},{name:"data",type:"string"}]},{name:"dispatchSyncEvent",parameters:[{name:"origin",type:"string"},{name:"registrationId",type:"string"},{name:"tag",type:"string"},{name:"lastChance",type:"boolean"}]}],events:[{name:"workerRegistrationUpdated",parameters:[{name:"registrations",type:"array",items:{$ref:"ServiceWorkerRegistration"}}]},{name:"workerVersionUpdated",parameters:[{name:"versions",type:"array",items:{$ref:"ServiceWorkerVersion"}}]},{name:"workerErrorReported",parameters:[{name:"errorMessage",$ref:"ServiceWorkerErrorMessage"}]}]},{domain:"Input",types:[{id:"TouchPoint",type:"object",experimental:!0,properties:[{name:"state",type:"string",enum:["touchPressed","touchReleased","touchMoved","touchStationary","touchCancelled"],description:"State of the touch point."},{name:"x",type:"integer",description:"X coordinate of the event relative to the main frame's viewport."},{name:"y",type:"integer",description:"Y coordinate of the event relative to the main frame's viewport. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport."},{name:"radiusX",type:"integer",optional:!0,description:"X radius of the touch area (default: 1)."},{name:"radiusY",type:"integer",optional:!0,description:"Y radius of the touch area (default: 1)."},{name:"rotationAngle",type:"number",optional:!0,description:"Rotation angle (default: 0.0)."},{name:"force",type:"number",optional:!0,description:"Force (default: 1.0)."},{name:"id",type:"number",optional:!0,description:"Identifier used to track touch sources between events, must be unique within an event."}]},{id:"GestureSourceType",type:"string",experimental:!0,enum:["default","touch","mouse"]}],commands:[{name:"setIgnoreInputEvents",parameters:[{name:"ignore",type:"boolean",description:"Ignores input events processing when set to true."}],description:"Ignores input events (useful while auditing page)."},{name:"dispatchKeyEvent",parameters:[{name:"type",type:"string",enum:["keyDown","keyUp","rawKeyDown","char"],description:"Type of the key event."},{name:"modifiers",type:"integer",optional:!0,description:"Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0)."},{name:"timestamp",type:"number",optional:!0,description:"Time at which the event occurred. Measured in UTC time in seconds since January 1, 1970 (default: current time)."},{name:"text",type:"string",optional:!0,description:'Text as generated by processing a virtual key code with a keyboard layout. Not needed for for keyUp and rawKeyDown events (default: "")'},{name:"unmodifiedText",type:"string",optional:!0,description:'Text that would have been generated by the keyboard if no modifiers were pressed (except for shift). Useful for shortcut (accelerator) key handling (default: "").'},{name:"keyIdentifier",type:"string",optional:!0,description:"Unique key identifier (e.g., 'U+0041') (default: \"\")."},{name:"code",type:"string",optional:!0,description:"Unique DOM defined string value for each physical key (e.g., 'KeyA') (default: \"\")." +},{name:"key",type:"string",optional:!0,description:"Unique DOM defined string value describing the meaning of the key in the context of active modifiers, keyboard layout, etc (e.g., 'AltGr') (default: \"\")."},{name:"windowsVirtualKeyCode",type:"integer",optional:!0,description:"Windows virtual key code (default: 0)."},{name:"nativeVirtualKeyCode",type:"integer",optional:!0,description:"Native virtual key code (default: 0)."},{name:"autoRepeat",type:"boolean",optional:!0,description:"Whether the event was generated from auto repeat (default: false)."},{name:"isKeypad",type:"boolean",optional:!0,description:"Whether the event was generated from the keypad (default: false)."},{name:"isSystemKey",type:"boolean",optional:!0,description:"Whether the event was a system key event (default: false)."}],description:"Dispatches a key event to the page."},{name:"dispatchMouseEvent",parameters:[{name:"type",type:"string",enum:["mousePressed","mouseReleased","mouseMoved"],description:"Type of the mouse event."},{name:"x",type:"integer",description:"X coordinate of the event relative to the main frame's viewport."},{name:"y",type:"integer",description:"Y coordinate of the event relative to the main frame's viewport. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport."},{name:"modifiers",type:"integer",optional:!0,description:"Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0)."},{name:"timestamp",type:"number",optional:!0,description:"Time at which the event occurred. Measured in UTC time in seconds since January 1, 1970 (default: current time)."},{name:"button",type:"string",enum:["none","left","middle","right"],optional:!0,description:'Mouse button (default: "none").'},{name:"clickCount",type:"integer",optional:!0,description:"Number of times the mouse button was clicked (default: 0)."}],description:"Dispatches a mouse event to the page."},{name:"dispatchTouchEvent",experimental:!0,parameters:[{name:"type",type:"string",enum:["touchStart","touchEnd","touchMove"],description:"Type of the touch event."},{name:"touchPoints",type:"array",items:{$ref:"TouchPoint"},description:"Touch points."},{name:"modifiers",type:"integer",optional:!0,description:"Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0)."},{name:"timestamp",type:"number",optional:!0,description:"Time at which the event occurred. Measured in UTC time in seconds since January 1, 1970 (default: current time)."}],description:"Dispatches a touch event to the page."},{name:"emulateTouchFromMouseEvent",experimental:!0,parameters:[{name:"type",type:"string",enum:["mousePressed","mouseReleased","mouseMoved","mouseWheel"],description:"Type of the mouse event."},{name:"x",type:"integer",description:"X coordinate of the mouse pointer in DIP."},{name:"y",type:"integer",description:"Y coordinate of the mouse pointer in DIP."},{name:"timestamp",type:"number",description:"Time at which the event occurred. Measured in UTC time in seconds since January 1, 1970."},{name:"button",type:"string",enum:["none","left","middle","right"],description:"Mouse button."},{name:"deltaX",type:"number",optional:!0,description:"X delta in DIP for mouse wheel event (default: 0)."},{name:"deltaY",type:"number",optional:!0,description:"Y delta in DIP for mouse wheel event (default: 0)."},{name:"modifiers",type:"integer",optional:!0,description:"Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0)."},{name:"clickCount",type:"integer",optional:!0,description:"Number of times the mouse button was clicked (default: 0)."}],description:"Emulates touch event from the mouse event parameters."},{name:"synthesizePinchGesture",parameters:[{name:"x",type:"integer",description:"X coordinate of the start of the gesture in CSS pixels."},{name:"y",type:"integer",description:"Y coordinate of the start of the gesture in CSS pixels."},{name:"scaleFactor",type:"number",description:"Relative scale factor after zooming (>1.0 zooms in, <1.0 zooms out)."},{name:"relativeSpeed",type:"integer",optional:!0,description:"Relative pointer speed in pixels per second (default: 800)."},{name:"gestureSourceType",$ref:"GestureSourceType",optional:!0,description:"Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type)."}],description:"Synthesizes a pinch gesture over a time period by issuing appropriate touch events.",experimental:!0},{name:"synthesizeScrollGesture",parameters:[{name:"x",type:"integer",description:"X coordinate of the start of the gesture in CSS pixels."},{name:"y",type:"integer",description:"Y coordinate of the start of the gesture in CSS pixels."},{name:"xDistance",type:"integer",optional:!0,description:"The distance to scroll along the X axis (positive to scroll left)."},{name:"yDistance",type:"integer",optional:!0,description:"The distance to scroll along the Y axis (positive to scroll up)."},{name:"xOverscroll",type:"integer",optional:!0,description:"The number of additional pixels to scroll back along the X axis, in addition to the given distance."},{name:"yOverscroll",type:"integer",optional:!0,description:"The number of additional pixels to scroll back along the Y axis, in addition to the given distance."},{name:"preventFling",type:"boolean",optional:!0,description:"Prevent fling (default: true)."},{name:"speed",type:"integer",optional:!0,description:"Swipe speed in pixels per second (default: 800)."},{name:"gestureSourceType",$ref:"GestureSourceType",optional:!0,description:"Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type)."},{name:"repeatCount",type:"integer",optional:!0,description:"The number of times to repeat the gesture (default: 0)."},{name:"repeatDelayMs",type:"integer",optional:!0,description:"The number of milliseconds delay between each repeat. (default: 250)."},{name:"interactionMarkerName",type:"string",optional:!0,description:'The name of the interaction markers to generate, if not empty (default: "").'}],description:"Synthesizes a scroll gesture over a time period by issuing appropriate touch events.",experimental:!0},{name:"synthesizeTapGesture",parameters:[{name:"x",type:"integer",description:"X coordinate of the start of the gesture in CSS pixels."},{name:"y",type:"integer",description:"Y coordinate of the start of the gesture in CSS pixels."},{name:"duration",type:"integer",optional:!0,description:"Duration between touchdown and touchup events in ms (default: 50)."},{name:"tapCount",type:"integer",optional:!0,description:"Number of times to perform the tap (e.g. 2 for double tap, default: 1)."},{name:"gestureSourceType",$ref:"GestureSourceType",optional:!0,description:"Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type)."}],description:"Synthesizes a tap gesture over a time period by issuing appropriate touch events.",experimental:!0}],events:[]},{domain:"LayerTree",experimental:!0,dependencies:["DOM"],types:[{id:"LayerId",type:"string",description:"Unique Layer identifier."},{id:"SnapshotId",type:"string",description:"Unique snapshot identifier."},{id:"ScrollRect",type:"object",description:"Rectangle where scrolling happens on the main thread.",properties:[{name:"rect",$ref:"DOM.Rect",description:"Rectangle itself."},{name:"type",type:"string",enum:["RepaintsOnScroll","TouchEventHandler","WheelEventHandler"],description:"Reason for rectangle to force scrolling on the main thread"}]},{id:"PictureTile",type:"object",description:"Serialized fragment of layer picture along with its offset within the layer.",properties:[{name:"x",type:"number",description:"Offset from owning layer left boundary"},{name:"y",type:"number",description:"Offset from owning layer top boundary"},{name:"picture",type:"string",description:"Base64-encoded snapshot data."}]},{id:"Layer",type:"object",description:"Information about a compositing layer.",properties:[{name:"layerId",$ref:"LayerId",description:"The unique id for this layer."},{name:"parentLayerId",$ref:"LayerId",optional:!0,description:"The id of parent (not present for root)."},{name:"backendNodeId",$ref:"DOM.BackendNodeId",optional:!0,description:"The backend id for the node associated with this layer."},{name:"offsetX",type:"number",description:"Offset from parent layer, X coordinate."},{name:"offsetY",type:"number",description:"Offset from parent layer, Y coordinate."},{name:"width",type:"number",description:"Layer width."},{name:"height",type:"number",description:"Layer height."},{name:"transform",type:"array",items:{type:"number"},minItems:16,maxItems:16,optional:!0,description:"Transformation matrix for layer, default is identity matrix"},{name:"anchorX",type:"number",optional:!0,description:"Transform anchor point X, absent if no transform specified"},{name:"anchorY",type:"number",optional:!0,description:"Transform anchor point Y, absent if no transform specified"},{name:"anchorZ",type:"number",optional:!0,description:"Transform anchor point Z, absent if no transform specified"},{name:"paintCount",type:"integer",description:"Indicates how many time this layer has painted."},{name:"drawsContent",type:"boolean",description:"Indicates whether this layer hosts any content, rather than being used for transform/scrolling purposes only."},{name:"invisible",type:"boolean",optional:!0,description:"Set if layer is not visible."},{name:"scrollRects",type:"array",items:{$ref:"ScrollRect"},optional:!0,description:"Rectangles scrolling on main thread only."}]},{id:"PaintProfile",type:"array",description:"Array of timings, one per paint step.",items:{type:"number",description:"A time in seconds since the end of previous step (for the first step, time since painting started)"}}],commands:[{name:"enable",description:"Enables compositing tree inspection."},{name:"disable",description:"Disables compositing tree inspection."},{name:"compositingReasons",parameters:[{name:"layerId",$ref:"LayerId",description:"The id of the layer for which we want to get the reasons it was composited."}],description:"Provides the reasons why the given layer was composited.",returns:[{name:"compositingReasons",type:"array",items:{type:"string"},description:"A list of strings specifying reasons for the given layer to become composited."}]},{name:"makeSnapshot",parameters:[{name:"layerId",$ref:"LayerId",description:"The id of the layer."}],description:"Returns the layer snapshot identifier.",returns:[{name:"snapshotId",$ref:"SnapshotId",description:"The id of the layer snapshot."}]},{name:"loadSnapshot",parameters:[{name:"tiles",type:"array",items:{$ref:"PictureTile"},minItems:1,description:"An array of tiles composing the snapshot."}],description:"Returns the snapshot identifier.",returns:[{name:"snapshotId",$ref:"SnapshotId",description:"The id of the snapshot."}]},{name:"releaseSnapshot",parameters:[{name:"snapshotId",$ref:"SnapshotId",description:"The id of the layer snapshot."}],description:"Releases layer snapshot captured by the back-end."},{name:"profileSnapshot",parameters:[{name:"snapshotId",$ref:"SnapshotId",description:"The id of the layer snapshot."},{name:"minRepeatCount",type:"integer",optional:!0,description:"The maximum number of times to replay the snapshot (1, if not specified)."},{name:"minDuration",type:"number",optional:!0,description:"The minimum duration (in seconds) to replay the snapshot."},{name:"clipRect",$ref:"DOM.Rect",optional:!0,description:"The clip rectangle to apply when replaying the snapshot."}],returns:[{name:"timings",type:"array",items:{$ref:"PaintProfile"},description:"The array of paint profiles, one per run."}]},{name:"replaySnapshot",parameters:[{name:"snapshotId",$ref:"SnapshotId",description:"The id of the layer snapshot."},{name:"fromStep",type:"integer",optional:!0,description:"The first step to replay from (replay from the very start if not specified)."},{name:"toStep",type:"integer",optional:!0,description:"The last step to replay to (replay till the end if not specified)."},{name:"scale",type:"number",optional:!0,description:"The scale to apply while replaying (defaults to 1)."}],description:"Replays the layer snapshot and returns the resulting bitmap.",returns:[{name:"dataURL",type:"string",description:"A data: URL for resulting image."}]},{name:"snapshotCommandLog",parameters:[{name:"snapshotId",$ref:"SnapshotId",description:"The id of the layer snapshot."}],description:"Replays the layer snapshot and returns canvas log.",returns:[{name:"commandLog",type:"array",items:{type:"object"},description:"The array of canvas function calls."}]}],events:[{name:"layerTreeDidChange",parameters:[{name:"layers",type:"array",items:{$ref:"Layer"},optional:!0,description:"Layer tree, absent if not in the comspositing mode."}]},{name:"layerPainted",parameters:[{name:"layerId",$ref:"LayerId",description:"The id of the painted layer."},{name:"clip",$ref:"DOM.Rect",description:"Clip rectangle."}]}]},{domain:"DeviceOrientation",experimental:!0,commands:[{name:"setDeviceOrientationOverride",description:"Overrides the Device Orientation.",parameters:[{name:"alpha",type:"number",description:"Mock alpha"},{name:"beta",type:"number",description:"Mock beta"},{name:"gamma",type:"number",description:"Mock gamma"}]},{name:"clearDeviceOrientationOverride",description:"Clears the overridden Device Orientation."}]},{domain:"Tracing",dependencies:["IO"],experimental:!0,types:[{id:"MemoryDumpConfig",type:"object",description:'Configuration for memory dump. Used only when "memory-infra" category is enabled.'},{id:"TraceConfig",type:"object",properties:[{name:"recordMode",type:"string",optional:!0,enum:["recordUntilFull","recordContinuously","recordAsMuchAsPossible","echoToConsole"],description:"Controls how the trace buffer stores data."},{name:"enableSampling",type:"boolean",optional:!0,description:"Turns on JavaScript stack sampling."},{name:"enableSystrace",type:"boolean",optional:!0,description:"Turns on system tracing."},{name:"enableArgumentFilter",type:"boolean",optional:!0,description:"Turns on argument filter."},{name:"includedCategories",type:"array",items:{type:"string"},optional:!0,description:"Included category filters."},{name:"excludedCategories",type:"array",items:{type:"string"},optional:!0,description:"Excluded category filters."},{name:"syntheticDelays",type:"array",items:{type:"string"},optional:!0,description:"Configuration to synthesize the delays in tracing."},{name:"memoryDumpConfig",$ref:"MemoryDumpConfig",optional:!0,description:'Configuration for memory dump triggers. Used only when "memory-infra" category is enabled.'}]}],commands:[{name:"start",description:"Start trace events collection.",parameters:[{name:"categories",type:"string",optional:!0,deprecated:!0,description:"Category/tag filter"},{name:"options",type:"string",optional:!0,deprecated:!0,description:"Tracing options"},{name:"bufferUsageReportingInterval",type:"number",optional:!0,description:"If set, the agent will issue bufferUsage events at this interval, specified in milliseconds"},{name:"transferMode",type:"string",enum:["ReportEvents","ReturnAsStream"],optional:!0,description:"Whether to report trace events as series of dataCollected events or to save trace to a stream (defaults to ReportEvents)."},{name:"traceConfig",$ref:"TraceConfig",optional:!0,description:""}]},{name:"end",description:"Stop trace events collection."},{name:"getCategories",description:"Gets supported tracing categories.",returns:[{name:"categories",type:"array",items:{type:"string"},description:"A list of supported tracing categories."}]},{name:"requestMemoryDump",description:"Request a global memory dump.",returns:[{name:"dumpGuid",type:"string",description:"GUID of the resulting global memory dump."},{name:"success",type:"boolean",description:"True iff the global memory dump succeeded."}]},{name:"recordClockSyncMarker",description:"Record a clock sync marker in the trace.",parameters:[{name:"syncId",type:"string",description:"The ID of this clock sync marker"}]}],events:[{name:"dataCollected",parameters:[{name:"value",type:"array",items:{type:"object"}}],description:"Contains an bucket of collected trace events. When tracing is stopped collected events will be send as a sequence of dataCollected events followed by tracingComplete event."},{name:"tracingComplete",description:"Signals that tracing is stopped and there is no trace buffers pending flush, all data were delivered via dataCollected events.",parameters:[{name:"stream",$ref:"IO.StreamHandle",optional:!0,description:"A handle of the stream that holds resulting trace data."}]},{name:"bufferUsage",parameters:[{name:"percentFull",type:"number",optional:!0,description:"A number in range [0..1] that indicates the used size of event buffer as a fraction of its total size."},{name:"eventCount",type:"number",optional:!0,description:"An approximate number of events in the trace log."},{name:"value",type:"number",optional:!0,description:"A number in range [0..1] that indicates the used size of event buffer as a fraction of its total size."}]}]},{domain:"Animation",experimental:!0,dependencies:["Runtime","DOM"],types:[{id:"Animation",type:"object",experimental:!0,properties:[{name:"id",type:"string",description:"Animation's id."},{name:"name",type:"string",description:"Animation's name."},{name:"pausedState",type:"boolean",experimental:!0,description:"Animation's internal paused state."},{name:"playState",type:"string",description:"Animation's play state."},{name:"playbackRate",type:"number",description:"Animation's playback rate."},{name:"startTime",type:"number",description:"Animation's start time."},{name:"currentTime",type:"number",description:"Animation's current time."},{name:"source",$ref:"AnimationEffect",description:"Animation's source animation node."},{name:"type",type:"string",enum:["CSSTransition","CSSAnimation","WebAnimation"],description:"Animation type of Animation."},{name:"cssId",type:"string",optional:!0,description:"A unique ID for Animation representing the sources that triggered this CSS animation/transition."}],description:"Animation instance."},{id:"AnimationEffect",type:"object",experimental:!0,properties:[{name:"delay",type:"number",description:"AnimationEffect's delay."},{name:"endDelay",type:"number",description:"AnimationEffect's end delay."},{name:"iterationStart",type:"number",description:"AnimationEffect's iteration start."},{name:"iterations",type:"number",description:"AnimationEffect's iterations."},{name:"duration",type:"number",description:"AnimationEffect's iteration duration."},{name:"direction",type:"string",description:"AnimationEffect's playback direction."},{name:"fill",type:"string",description:"AnimationEffect's fill mode."},{name:"backendNodeId",$ref:"DOM.BackendNodeId",description:"AnimationEffect's target node."},{name:"keyframesRule",$ref:"KeyframesRule",optional:!0,description:"AnimationEffect's keyframes."},{name:"easing",type:"string",description:"AnimationEffect's timing function."}],description:"AnimationEffect instance"},{id:"KeyframesRule",type:"object",properties:[{name:"name",type:"string",optional:!0,description:"CSS keyframed animation's name."},{name:"keyframes",type:"array",items:{$ref:"KeyframeStyle"},description:"List of animation keyframes."}],description:"Keyframes Rule"},{id:"KeyframeStyle",type:"object",properties:[{name:"offset",type:"string",description:"Keyframe's time offset."},{name:"easing",type:"string",description:"AnimationEffect's timing function."}],description:"Keyframe Style"}],commands:[{name:"enable",description:"Enables animation domain notifications."},{name:"disable",description:"Disables animation domain notifications."},{name:"getPlaybackRate",returns:[{name:"playbackRate",type:"number",description:"Playback rate for animations on page."}],description:"Gets the playback rate of the document timeline."},{name:"setPlaybackRate",parameters:[{name:"playbackRate",type:"number",description:"Playback rate for animations on page"}],description:"Sets the playback rate of the document timeline."},{name:"getCurrentTime",parameters:[{name:"id",type:"string",description:"Id of animation."}],returns:[{name:"currentTime",type:"number",description:"Current time of the page."}],description:"Returns the current time of the an animation."},{name:"setPaused",parameters:[{name:"animations",type:"array",items:{type:"string"},description:"Animations to set the pause state of."},{name:"paused",type:"boolean",description:"Paused state to set to."}],description:"Sets the paused state of a set of animations."},{name:"setTiming",parameters:[{name:"animationId",type:"string",description:"Animation id."},{name:"duration",type:"number",description:"Duration of the animation."},{name:"delay",type:"number",description:"Delay of the animation."}],description:"Sets the timing of an animation node."},{name:"seekAnimations",parameters:[{name:"animations",type:"array",items:{type:"string"},description:"List of animation ids to seek."},{name:"currentTime",type:"number",description:"Set the current time of each animation."}],description:"Seek a set of animations to a particular time within each animation."},{name:"releaseAnimations",parameters:[{name:"animations",type:"array",items:{type:"string"},description:"List of animation ids to seek."}],description:"Releases a set of animations to no longer be manipulated."},{name:"resolveAnimation",parameters:[{name:"animationId",type:"string",description:"Animation id."}],returns:[{name:"remoteObject",$ref:"Runtime.RemoteObject",description:"Corresponding remote object."}],description:"Gets the remote object of the Animation."}],events:[{name:"animationCreated",parameters:[{name:"id",type:"string",description:"Id of the animation that was created."}],description:"Event for each animation that has been created."},{name:"animationStarted",parameters:[{name:"animation",$ref:"Animation",description:"Animation that was started."}],description:"Event for animation that has been started."},{name:"animationCanceled",parameters:[{name:"id",type:"string",description:"Id of the animation that was cancelled."}],description:"Event for when an animation has been cancelled."}]},{domain:"Accessibility",experimental:!0,dependencies:["DOM"],types:[{id:"AXNodeId",type:"string",description:"Unique accessibility node identifier."},{id:"AXValueType",type:"string",enum:["boolean","tristate","booleanOrUndefined","idref","idrefList","integer","node","nodeList","number","string","computedString","token","tokenList","domRelation","role","internalRole","valueUndefined"],description:"Enum of possible property types."},{id:"AXValueSourceType",type:"string",enum:["attribute","implicit","style","contents","placeholder","relatedElement"],description:"Enum of possible property sources."},{id:"AXValueNativeSourceType",type:"string",enum:["figcaption","label","labelfor","labelwrapped","legend","tablecaption","title","other"],description:"Enum of possible native property sources (as a subtype of a particular AXValueSourceType)."},{id:"AXValueSource",type:"object",properties:[{name:"type",$ref:"AXValueSourceType",description:"What type of source this is."},{name:"value",$ref:"AXValue",description:"The value of this property source.",optional:!0},{name:"attribute",type:"string",description:"The name of the relevant attribute, if any.",optional:!0},{name:"attributeValue",$ref:"AXValue",description:"The value of the relevant attribute, if any.",optional:!0},{name:"superseded",type:"boolean",description:"Whether this source is superseded by a higher priority source.",optional:!0},{name:"nativeSource",$ref:"AXValueNativeSourceType",description:"The native markup source for this value, e.g. a